Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
This commit is contained in:
44
blockchain/README.md
Normal file
44
blockchain/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Sankofa Phoenix Blockchain
|
||||
|
||||
Enterprise Ethereum Alliance (EEA) blockchain implementation for Sankofa Phoenix.
|
||||
|
||||
## Platform Choice
|
||||
|
||||
**Hyperledger Besu** - Selected as the blockchain platform
|
||||
- Enterprise-grade Ethereum client
|
||||
- Permissioning and privacy features
|
||||
- EEA standards compliant
|
||||
- Active development and support
|
||||
|
||||
## Development Toolchain
|
||||
|
||||
### Prerequisites
|
||||
- Java 17+
|
||||
- Docker
|
||||
- Node.js 18+ (for development tools)
|
||||
|
||||
### Tools
|
||||
- **Hardhat**: Smart contract development framework
|
||||
- **Truffle**: Alternative development framework
|
||||
- **Web3.js/Ethers.js**: Blockchain interaction libraries
|
||||
- **Besu**: Blockchain client
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
blockchain/
|
||||
├── contracts/ # Smart contracts (Solidity)
|
||||
├── scripts/ # Deployment and utility scripts
|
||||
├── tests/ # Smart contract tests
|
||||
├── hardhat.config.js # Hardhat configuration
|
||||
├── network-config/ # Besu network configuration
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install dependencies: `npm install`
|
||||
2. Compile contracts: `npx hardhat compile`
|
||||
3. Run tests: `npx hardhat test`
|
||||
4. Deploy to test network: `npx hardhat deploy --network besu`
|
||||
|
||||
140
blockchain/contracts/Billing.sol
Normal file
140
blockchain/contracts/Billing.sol
Normal file
@@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/**
|
||||
* @title Billing
|
||||
* @dev Smart contract for tracking billing and resource usage costs
|
||||
*/
|
||||
contract Billing {
|
||||
struct UsageRecord {
|
||||
string resourceId;
|
||||
string resourceType;
|
||||
uint256 startTime;
|
||||
uint256 endTime;
|
||||
uint256 cost; // Cost in smallest unit (wei-like)
|
||||
string currency;
|
||||
address billedTo;
|
||||
}
|
||||
|
||||
struct Bill {
|
||||
address billedTo;
|
||||
uint256 periodStart;
|
||||
uint256 periodEnd;
|
||||
uint256 totalCost;
|
||||
string currency;
|
||||
bool paid;
|
||||
uint256 paidAt;
|
||||
}
|
||||
|
||||
mapping(string => UsageRecord[]) public resourceUsage;
|
||||
mapping(address => Bill[]) public bills;
|
||||
mapping(string => uint256) public resourceCosts;
|
||||
|
||||
event UsageRecorded(
|
||||
string indexed resourceId,
|
||||
address indexed billedTo,
|
||||
uint256 cost,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
event BillGenerated(
|
||||
address indexed billedTo,
|
||||
uint256 billId,
|
||||
uint256 totalCost,
|
||||
uint256 periodStart,
|
||||
uint256 periodEnd
|
||||
);
|
||||
|
||||
event BillPaid(
|
||||
address indexed billedTo,
|
||||
uint256 billId,
|
||||
uint256 paidAt
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Record resource usage and cost
|
||||
*/
|
||||
function recordUsage(
|
||||
string memory resourceId,
|
||||
string memory resourceType,
|
||||
uint256 startTime,
|
||||
uint256 endTime,
|
||||
uint256 cost,
|
||||
string memory currency,
|
||||
address billedTo
|
||||
) public returns (bool) {
|
||||
UsageRecord memory record = UsageRecord({
|
||||
resourceId: resourceId,
|
||||
resourceType: resourceType,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
cost: cost,
|
||||
currency: currency,
|
||||
billedTo: billedTo
|
||||
});
|
||||
|
||||
resourceUsage[resourceId].push(record);
|
||||
resourceCosts[resourceId] += cost;
|
||||
|
||||
emit UsageRecorded(resourceId, billedTo, cost, block.timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Generate a bill for a billing period
|
||||
*/
|
||||
function generateBill(
|
||||
address billedTo,
|
||||
uint256 periodStart,
|
||||
uint256 periodEnd
|
||||
) public returns (uint256) {
|
||||
uint256 totalCost = 0;
|
||||
|
||||
// Calculate total cost from all usage records in period
|
||||
// This is simplified - actual implementation would aggregate all resources
|
||||
|
||||
uint256 billId = bills[billedTo].length;
|
||||
Bill memory bill = Bill({
|
||||
billedTo: billedTo,
|
||||
periodStart: periodStart,
|
||||
periodEnd: periodEnd,
|
||||
totalCost: totalCost,
|
||||
currency: "USD",
|
||||
paid: false,
|
||||
paidAt: 0
|
||||
});
|
||||
|
||||
bills[billedTo].push(bill);
|
||||
|
||||
emit BillGenerated(billedTo, billId, totalCost, periodStart, periodEnd);
|
||||
return billId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Mark a bill as paid
|
||||
*/
|
||||
function payBill(address billedTo, uint256 billId) public {
|
||||
require(billId < bills[billedTo].length, "Bill does not exist");
|
||||
require(!bills[billedTo][billId].paid, "Bill already paid");
|
||||
|
||||
bills[billedTo][billId].paid = true;
|
||||
bills[billedTo][billId].paidAt = block.timestamp;
|
||||
|
||||
emit BillPaid(billedTo, billId, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get total cost for a resource
|
||||
*/
|
||||
function getResourceTotalCost(string memory resourceId) public view returns (uint256) {
|
||||
return resourceCosts[resourceId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get all bills for an address
|
||||
*/
|
||||
function getBills(address billedTo) public view returns (Bill[] memory) {
|
||||
return bills[billedTo];
|
||||
}
|
||||
}
|
||||
|
||||
124
blockchain/contracts/Compliance.sol
Normal file
124
blockchain/contracts/Compliance.sol
Normal file
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/**
|
||||
* @title Compliance
|
||||
* @dev Smart contract for tracking compliance and audit requirements
|
||||
*/
|
||||
contract Compliance {
|
||||
enum ComplianceStatus {
|
||||
COMPLIANT,
|
||||
NON_COMPLIANT,
|
||||
PENDING_REVIEW,
|
||||
EXEMPTED
|
||||
}
|
||||
|
||||
enum ComplianceFramework {
|
||||
GDPR,
|
||||
HIPAA,
|
||||
SOC2,
|
||||
ISO27001,
|
||||
CUSTOM
|
||||
}
|
||||
|
||||
struct ComplianceRecord {
|
||||
string resourceId;
|
||||
ComplianceFramework framework;
|
||||
ComplianceStatus status;
|
||||
string findings;
|
||||
address reviewedBy;
|
||||
uint256 reviewedAt;
|
||||
uint256 createdAt;
|
||||
}
|
||||
|
||||
mapping(string => ComplianceRecord[]) public complianceRecords;
|
||||
mapping(string => mapping(ComplianceFramework => ComplianceStatus)) public resourceCompliance;
|
||||
|
||||
event ComplianceChecked(
|
||||
string indexed resourceId,
|
||||
ComplianceFramework framework,
|
||||
ComplianceStatus status,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
event ComplianceReviewed(
|
||||
string indexed resourceId,
|
||||
ComplianceFramework framework,
|
||||
ComplianceStatus status,
|
||||
address indexed reviewedBy,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Record a compliance check
|
||||
*/
|
||||
function recordComplianceCheck(
|
||||
string memory resourceId,
|
||||
ComplianceFramework framework,
|
||||
ComplianceStatus status,
|
||||
string memory findings
|
||||
) public returns (bool) {
|
||||
ComplianceRecord memory record = ComplianceRecord({
|
||||
resourceId: resourceId,
|
||||
framework: framework,
|
||||
status: status,
|
||||
findings: findings,
|
||||
reviewedBy: address(0),
|
||||
reviewedAt: 0,
|
||||
createdAt: block.timestamp
|
||||
});
|
||||
|
||||
complianceRecords[resourceId].push(record);
|
||||
resourceCompliance[resourceId][framework] = status;
|
||||
|
||||
emit ComplianceChecked(resourceId, framework, status, block.timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Review and update compliance status
|
||||
*/
|
||||
function reviewCompliance(
|
||||
string memory resourceId,
|
||||
ComplianceFramework framework,
|
||||
ComplianceStatus status,
|
||||
string memory findings
|
||||
) public {
|
||||
ComplianceRecord memory record = ComplianceRecord({
|
||||
resourceId: resourceId,
|
||||
framework: framework,
|
||||
status: status,
|
||||
findings: findings,
|
||||
reviewedBy: msg.sender,
|
||||
reviewedAt: block.timestamp,
|
||||
createdAt: block.timestamp
|
||||
});
|
||||
|
||||
complianceRecords[resourceId].push(record);
|
||||
resourceCompliance[resourceId][framework] = status;
|
||||
|
||||
emit ComplianceReviewed(resourceId, framework, status, msg.sender, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get compliance status for a resource and framework
|
||||
*/
|
||||
function getComplianceStatus(
|
||||
string memory resourceId,
|
||||
ComplianceFramework framework
|
||||
) public view returns (ComplianceStatus) {
|
||||
return resourceCompliance[resourceId][framework];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get all compliance records for a resource
|
||||
*/
|
||||
function getComplianceRecords(string memory resourceId)
|
||||
public
|
||||
view
|
||||
returns (ComplianceRecord[] memory)
|
||||
{
|
||||
return complianceRecords[resourceId];
|
||||
}
|
||||
}
|
||||
|
||||
129
blockchain/contracts/IdentityManagement.sol
Normal file
129
blockchain/contracts/IdentityManagement.sol
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/**
|
||||
* @title IdentityManagement
|
||||
* @dev Smart contract for identity and access management on the blockchain
|
||||
*/
|
||||
contract IdentityManagement {
|
||||
enum Role {
|
||||
ADMIN,
|
||||
USER,
|
||||
VIEWER
|
||||
}
|
||||
|
||||
struct Identity {
|
||||
address accountAddress;
|
||||
string userId;
|
||||
string email;
|
||||
string name;
|
||||
Role role;
|
||||
bool active;
|
||||
uint256 createdAt;
|
||||
uint256 updatedAt;
|
||||
}
|
||||
|
||||
mapping(address => Identity) public identities;
|
||||
mapping(string => address) public userIdToAddress;
|
||||
address[] public identityAddresses;
|
||||
|
||||
event IdentityCreated(
|
||||
address indexed accountAddress,
|
||||
string indexed userId,
|
||||
Role role,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
event IdentityUpdated(
|
||||
address indexed accountAddress,
|
||||
Role newRole,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
event IdentityDeactivated(
|
||||
address indexed accountAddress,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Create a new identity
|
||||
*/
|
||||
function createIdentity(
|
||||
address accountAddress,
|
||||
string memory userId,
|
||||
string memory email,
|
||||
string memory name,
|
||||
Role role
|
||||
) public returns (bool) {
|
||||
require(identities[accountAddress].accountAddress == address(0), "Identity already exists");
|
||||
require(userIdToAddress[userId] == address(0), "User ID already exists");
|
||||
|
||||
identities[accountAddress] = Identity({
|
||||
accountAddress: accountAddress,
|
||||
userId: userId,
|
||||
email: email,
|
||||
name: name,
|
||||
role: role,
|
||||
active: true,
|
||||
createdAt: block.timestamp,
|
||||
updatedAt: block.timestamp
|
||||
});
|
||||
|
||||
userIdToAddress[userId] = accountAddress;
|
||||
identityAddresses.push(accountAddress);
|
||||
|
||||
emit IdentityCreated(accountAddress, userId, role, block.timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update identity role
|
||||
*/
|
||||
function updateIdentityRole(address accountAddress, Role newRole) public {
|
||||
require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
|
||||
require(identities[accountAddress].active, "Identity is not active");
|
||||
|
||||
identities[accountAddress].role = newRole;
|
||||
identities[accountAddress].updatedAt = block.timestamp;
|
||||
|
||||
emit IdentityUpdated(accountAddress, newRole, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deactivate an identity
|
||||
*/
|
||||
function deactivateIdentity(address accountAddress) public {
|
||||
require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
|
||||
|
||||
identities[accountAddress].active = false;
|
||||
identities[accountAddress].updatedAt = block.timestamp;
|
||||
|
||||
emit IdentityDeactivated(accountAddress, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get identity by address
|
||||
*/
|
||||
function getIdentity(address accountAddress) public view returns (Identity memory) {
|
||||
require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
|
||||
return identities[accountAddress];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get identity by user ID
|
||||
*/
|
||||
function getIdentityByUserId(string memory userId) public view returns (Identity memory) {
|
||||
address accountAddress = userIdToAddress[userId];
|
||||
require(accountAddress != address(0), "User ID not found");
|
||||
return identities[accountAddress];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Check if address has role
|
||||
*/
|
||||
function hasRole(address accountAddress, Role role) public view returns (bool) {
|
||||
Identity memory identity = identities[accountAddress];
|
||||
return identity.active && identity.role == role;
|
||||
}
|
||||
}
|
||||
|
||||
123
blockchain/contracts/ResourceProvisioning.sol
Normal file
123
blockchain/contracts/ResourceProvisioning.sol
Normal file
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/**
|
||||
* @title ResourceProvisioning
|
||||
* @dev Smart contract for tracking resource provisioning on the blockchain
|
||||
*/
|
||||
contract ResourceProvisioning {
|
||||
enum ResourceType {
|
||||
VM,
|
||||
CONTAINER,
|
||||
STORAGE,
|
||||
NETWORK,
|
||||
SERVICE
|
||||
}
|
||||
|
||||
struct Resource {
|
||||
string resourceId;
|
||||
string region;
|
||||
string datacenter;
|
||||
ResourceType resourceType;
|
||||
uint256 provisionedAt;
|
||||
address provisionedBy;
|
||||
bool active;
|
||||
string metadata; // JSON string
|
||||
}
|
||||
|
||||
mapping(string => Resource) public resources;
|
||||
mapping(string => bool) public resourceExists;
|
||||
|
||||
string[] public resourceIds;
|
||||
|
||||
event ResourceProvisioned(
|
||||
string indexed resourceId,
|
||||
string region,
|
||||
ResourceType resourceType,
|
||||
address indexed provisionedBy,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
event ResourceDeprovisioned(
|
||||
string indexed resourceId,
|
||||
address indexed deprovisionedBy,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Provision a new resource
|
||||
*/
|
||||
function provisionResource(
|
||||
string memory resourceId,
|
||||
string memory region,
|
||||
string memory datacenter,
|
||||
ResourceType resourceType,
|
||||
string memory metadata
|
||||
) public returns (bool) {
|
||||
require(bytes(resourceId).length > 0, "Resource ID cannot be empty");
|
||||
require(!resourceExists[resourceId], "Resource already exists");
|
||||
|
||||
resources[resourceId] = Resource({
|
||||
resourceId: resourceId,
|
||||
region: region,
|
||||
datacenter: datacenter,
|
||||
resourceType: resourceType,
|
||||
provisionedAt: block.timestamp,
|
||||
provisionedBy: msg.sender,
|
||||
active: true,
|
||||
metadata: metadata
|
||||
});
|
||||
|
||||
resourceExists[resourceId] = true;
|
||||
resourceIds.push(resourceId);
|
||||
|
||||
emit ResourceProvisioned(
|
||||
resourceId,
|
||||
region,
|
||||
resourceType,
|
||||
msg.sender,
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deprovision a resource
|
||||
*/
|
||||
function deprovisionResource(string memory resourceId) public {
|
||||
require(resourceExists[resourceId], "Resource does not exist");
|
||||
require(resources[resourceId].active, "Resource already deprovisioned");
|
||||
|
||||
resources[resourceId].active = false;
|
||||
|
||||
emit ResourceDeprovisioned(resourceId, msg.sender, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get resource information
|
||||
*/
|
||||
function getResource(string memory resourceId)
|
||||
public
|
||||
view
|
||||
returns (Resource memory)
|
||||
{
|
||||
require(resourceExists[resourceId], "Resource does not exist");
|
||||
return resources[resourceId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get all resource IDs
|
||||
*/
|
||||
function getAllResourceIds() public view returns (string[] memory) {
|
||||
return resourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get resource count
|
||||
*/
|
||||
function getResourceCount() public view returns (uint256) {
|
||||
return resourceIds.length;
|
||||
}
|
||||
}
|
||||
|
||||
117
blockchain/docker-compose.besu.yml
Normal file
117
blockchain/docker-compose.besu.yml
Normal file
@@ -0,0 +1,117 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Hyperledger Besu Validator Node 1
|
||||
besu-validator-1:
|
||||
image: hyperledger/besu:latest
|
||||
container_name: besu-validator-1
|
||||
ports:
|
||||
- "8545:8545" # JSON-RPC
|
||||
- "8546:8546" # WebSocket
|
||||
- "30303:30303" # P2P
|
||||
volumes:
|
||||
- besu-validator-1-data:/var/lib/besu
|
||||
- ./network-config/genesis.json:/config/genesis.json
|
||||
- ./network-config/validator-1:/config/keys
|
||||
command:
|
||||
- --data-path=/var/lib/besu
|
||||
- --genesis-file=/config/genesis.json
|
||||
- --rpc-http-enabled=true
|
||||
- --rpc-http-host=0.0.0.0
|
||||
- --rpc-http-port=8545
|
||||
- --rpc-http-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --rpc-ws-enabled=true
|
||||
- --rpc-ws-host=0.0.0.0
|
||||
- --rpc-ws-port=8546
|
||||
- --rpc-ws-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --host-allowlist=*
|
||||
- --p2p-host=0.0.0.0
|
||||
- --p2p-port=30303
|
||||
- --min-gas-price=0
|
||||
- --network-id=2024
|
||||
- --bootnodes=enode://validator-1@besu-validator-1:30303
|
||||
networks:
|
||||
- besu-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8545"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Hyperledger Besu Validator Node 2
|
||||
besu-validator-2:
|
||||
image: hyperledger/besu:latest
|
||||
container_name: besu-validator-2
|
||||
ports:
|
||||
- "8547:8545"
|
||||
- "8548:8546"
|
||||
- "30304:30303"
|
||||
volumes:
|
||||
- besu-validator-2-data:/var/lib/besu
|
||||
- ./network-config/genesis.json:/config/genesis.json
|
||||
- ./network-config/validator-2:/config/keys
|
||||
command:
|
||||
- --data-path=/var/lib/besu
|
||||
- --genesis-file=/config/genesis.json
|
||||
- --rpc-http-enabled=true
|
||||
- --rpc-http-host=0.0.0.0
|
||||
- --rpc-http-port=8545
|
||||
- --rpc-http-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --rpc-ws-enabled=true
|
||||
- --rpc-ws-host=0.0.0.0
|
||||
- --rpc-ws-port=8546
|
||||
- --rpc-ws-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --host-allowlist=*
|
||||
- --p2p-host=0.0.0.0
|
||||
- --p2p-port=30303
|
||||
- --min-gas-price=0
|
||||
- --network-id=2024
|
||||
- --bootnodes=enode://validator-1@besu-validator-1:30303
|
||||
networks:
|
||||
- besu-network
|
||||
depends_on:
|
||||
- besu-validator-1
|
||||
|
||||
# Hyperledger Besu Validator Node 3
|
||||
besu-validator-3:
|
||||
image: hyperledger/besu:latest
|
||||
container_name: besu-validator-3
|
||||
ports:
|
||||
- "8549:8545"
|
||||
- "8550:8546"
|
||||
- "30305:30303"
|
||||
volumes:
|
||||
- besu-validator-3-data:/var/lib/besu
|
||||
- ./network-config/genesis.json:/config/genesis.json
|
||||
- ./network-config/validator-3:/config/keys
|
||||
command:
|
||||
- --data-path=/var/lib/besu
|
||||
- --genesis-file=/config/genesis.json
|
||||
- --rpc-http-enabled=true
|
||||
- --rpc-http-host=0.0.0.0
|
||||
- --rpc-http-port=8545
|
||||
- --rpc-http-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --rpc-ws-enabled=true
|
||||
- --rpc-ws-host=0.0.0.0
|
||||
- --rpc-ws-port=8546
|
||||
- --rpc-ws-api=ETH,NET,WEB3,ADMIN,EEA,PRIV,IBFT
|
||||
- --host-allowlist=*
|
||||
- --p2p-host=0.0.0.0
|
||||
- --p2p-port=30303
|
||||
- --min-gas-price=0
|
||||
- --network-id=2024
|
||||
- --bootnodes=enode://validator-1@besu-validator-1:30303
|
||||
networks:
|
||||
- besu-network
|
||||
depends_on:
|
||||
- besu-validator-1
|
||||
|
||||
networks:
|
||||
besu-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
besu-validator-1-data:
|
||||
besu-validator-2-data:
|
||||
besu-validator-3-data:
|
||||
|
||||
35
blockchain/docker-compose.yml
Normal file
35
blockchain/docker-compose.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
besu:
|
||||
image: hyperledger/besu:latest
|
||||
container_name: sankofa-besu-node
|
||||
ports:
|
||||
- "8545:8545" # JSON-RPC
|
||||
- "8546:8546" # WebSocket
|
||||
- "30303:30303" # P2P
|
||||
volumes:
|
||||
- besu-data:/var/lib/besu
|
||||
- ./network-config:/config
|
||||
command:
|
||||
- --data-path=/var/lib/besu
|
||||
- --network-id=2024
|
||||
- --rpc-http-enabled=true
|
||||
- --rpc-http-host=0.0.0.0
|
||||
- --rpc-http-port=8545
|
||||
- --rpc-http-api=ETH,NET,WEB3,ADMIN
|
||||
- --rpc-ws-enabled=true
|
||||
- --rpc-ws-host=0.0.0.0
|
||||
- --rpc-ws-port=8546
|
||||
- --p2p-port=30303
|
||||
- --genesis-file=/config/genesis.json
|
||||
- --logging=INFO
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8545"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
besu-data:
|
||||
|
||||
35
blockchain/hardhat.config.ts
Normal file
35
blockchain/hardhat.config.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { HardhatUserConfig } from 'hardhat/config'
|
||||
import '@nomicfoundation/hardhat-toolbox'
|
||||
import * as dotenv from 'dotenv'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
solidity: {
|
||||
version: '0.8.24',
|
||||
settings: {
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 200,
|
||||
},
|
||||
},
|
||||
},
|
||||
networks: {
|
||||
localhost: {
|
||||
url: 'http://localhost:8545',
|
||||
},
|
||||
testnet: {
|
||||
url: process.env.BESU_RPC_URL || 'http://localhost:8545',
|
||||
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
|
||||
},
|
||||
},
|
||||
paths: {
|
||||
sources: './contracts',
|
||||
tests: './tests',
|
||||
cache: './cache',
|
||||
artifacts: './artifacts',
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
|
||||
22
blockchain/network-config/genesis.json
Normal file
22
blockchain/network-config/genesis.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"config": {
|
||||
"chainId": 2024,
|
||||
"constantinopleFixBlock": 0,
|
||||
"ibft2": {
|
||||
"blockperiodseconds": 2,
|
||||
"epochlength": 30000,
|
||||
"requesttimeoutseconds": 10
|
||||
},
|
||||
"qip714block": 0
|
||||
},
|
||||
"nonce": "0x0",
|
||||
"timestamp": "0x0",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x1fffffffffffff",
|
||||
"difficulty": "0x1",
|
||||
"mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
|
||||
"alloc": {},
|
||||
"number": "0x0",
|
||||
"gasUsed": "0x0",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
30
blockchain/package.json
Normal file
30
blockchain/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "sankofa-phoenix-blockchain",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"compile": "hardhat compile",
|
||||
"test": "hardhat test",
|
||||
"deploy:local": "hardhat run scripts/deploy.ts --network localhost",
|
||||
"deploy:test": "hardhat run scripts/deploy.ts --network testnet",
|
||||
"node:start": "docker-compose up -d besu",
|
||||
"node:stop": "docker-compose down",
|
||||
"generate:types": "ts-node scripts/generate-types.ts",
|
||||
"compile:types": "hardhat compile && pnpm generate:types"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
|
||||
"@typechain/ethers-v6": "^0.5.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"hardhat": "^2.19.0",
|
||||
"typescript": "^5.4.0",
|
||||
"ts-node": "^10.9.0",
|
||||
"typechain": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^5.0.0",
|
||||
"ethers": "^6.9.0",
|
||||
"web3": "^4.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
49
blockchain/scripts/deploy.ts
Normal file
49
blockchain/scripts/deploy.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ethers } from 'hardhat'
|
||||
|
||||
async function main() {
|
||||
console.log('Deploying Sankofa Phoenix smart contracts...')
|
||||
|
||||
// Get deployer account
|
||||
const [deployer] = await ethers.getSigners()
|
||||
console.log('Deploying contracts with account:', deployer.address)
|
||||
console.log('Account balance:', (await ethers.provider.getBalance(deployer.address)).toString())
|
||||
|
||||
// Deploy ResourceProvisioning
|
||||
const ResourceProvisioningFactory = await ethers.getContractFactory('ResourceProvisioning')
|
||||
const resourceProvisioning = await ResourceProvisioningFactory.deploy()
|
||||
await resourceProvisioning.waitForDeployment()
|
||||
console.log('ResourceProvisioning deployed to:', await resourceProvisioning.getAddress())
|
||||
|
||||
// Deploy IdentityManagement
|
||||
const IdentityManagementFactory = await ethers.getContractFactory('IdentityManagement')
|
||||
const identityManagement = await IdentityManagementFactory.deploy()
|
||||
await identityManagement.waitForDeployment()
|
||||
console.log('IdentityManagement deployed to:', await identityManagement.getAddress())
|
||||
|
||||
// Deploy Billing
|
||||
const BillingFactory = await ethers.getContractFactory('Billing')
|
||||
const billing = await BillingFactory.deploy()
|
||||
await billing.waitForDeployment()
|
||||
console.log('Billing deployed to:', await billing.getAddress())
|
||||
|
||||
// Deploy Compliance
|
||||
const ComplianceFactory = await ethers.getContractFactory('Compliance')
|
||||
const compliance = await ComplianceFactory.deploy()
|
||||
await compliance.waitForDeployment()
|
||||
console.log('Compliance deployed to:', await compliance.getAddress())
|
||||
|
||||
console.log('\n✅ All contracts deployed successfully!')
|
||||
console.log('\nContract Addresses:')
|
||||
console.log(' ResourceProvisioning:', await resourceProvisioning.getAddress())
|
||||
console.log(' IdentityManagement:', await identityManagement.getAddress())
|
||||
console.log(' Billing:', await billing.getAddress())
|
||||
console.log(' Compliance:', await compliance.getAddress())
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
44
blockchain/scripts/generate-types.ts
Normal file
44
blockchain/scripts/generate-types.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Generate TypeScript types from compiled smart contracts
|
||||
* Run: pnpm exec ts-node scripts/generate-types.ts
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
async function generateTypes() {
|
||||
console.log('Generating TypeScript types from smart contracts...')
|
||||
|
||||
try {
|
||||
// Run typechain to generate types
|
||||
execSync('npx typechain --target ethers-v6 --out-dir ../api/src/types/contracts artifacts/contracts/**/*.json', {
|
||||
cwd: path.join(__dirname, '..'),
|
||||
stdio: 'inherit',
|
||||
})
|
||||
|
||||
console.log('✓ TypeScript types generated successfully')
|
||||
console.log('Types are available in: api/src/types/contracts/')
|
||||
|
||||
// Create index file for easy imports
|
||||
const typesDir = path.join(__dirname, '../../api/src/types/contracts')
|
||||
if (fs.existsSync(typesDir)) {
|
||||
const indexContent = `// Auto-generated contract type exports
|
||||
// This file is generated by scripts/generate-types.ts
|
||||
|
||||
export * from './ResourceProvisioning'
|
||||
export * from './IdentityManagement'
|
||||
export * from './Billing'
|
||||
export * from './Compliance'
|
||||
`
|
||||
fs.writeFileSync(path.join(typesDir, 'index.ts'), indexContent)
|
||||
console.log('✓ Created index.ts for contract types')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to generate types:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
generateTypes()
|
||||
|
||||
74
blockchain/tests/ResourceProvisioning.test.ts
Normal file
74
blockchain/tests/ResourceProvisioning.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { expect } from 'chai'
|
||||
import { ethers } from 'hardhat'
|
||||
import { ResourceProvisioning } from '../typechain-types'
|
||||
|
||||
describe('ResourceProvisioning', function () {
|
||||
let contract: ResourceProvisioning
|
||||
let owner: any
|
||||
let addr1: any
|
||||
|
||||
beforeEach(async function () {
|
||||
;[owner, addr1] = await ethers.getSigners()
|
||||
|
||||
const ResourceProvisioningFactory = await ethers.getContractFactory('ResourceProvisioning')
|
||||
contract = await ResourceProvisioningFactory.deploy()
|
||||
await contract.waitForDeployment()
|
||||
})
|
||||
|
||||
describe('Resource Provisioning', function () {
|
||||
it('Should provision a new resource', async function () {
|
||||
const tx = await contract.provisionResource(
|
||||
'resource-001',
|
||||
'us-east-1',
|
||||
'datacenter-1',
|
||||
0, // VM
|
||||
'{"cpu": 4, "memory": 8192}'
|
||||
)
|
||||
|
||||
await expect(tx)
|
||||
.to.emit(contract, 'ResourceProvisioned')
|
||||
.withArgs('resource-001', 'us-east-1', 0, owner.address, await ethers.provider.getBlockNumber())
|
||||
|
||||
const resource = await contract.getResource('resource-001')
|
||||
expect(resource.resourceId).to.equal('resource-001')
|
||||
expect(resource.active).to.equal(true)
|
||||
})
|
||||
|
||||
it('Should not allow provisioning duplicate resource', async function () {
|
||||
await contract.provisionResource(
|
||||
'resource-001',
|
||||
'us-east-1',
|
||||
'datacenter-1',
|
||||
0,
|
||||
'{}'
|
||||
)
|
||||
|
||||
await expect(
|
||||
contract.provisionResource(
|
||||
'resource-001',
|
||||
'us-east-1',
|
||||
'datacenter-1',
|
||||
0,
|
||||
'{}'
|
||||
)
|
||||
).to.be.revertedWith('Resource already exists')
|
||||
})
|
||||
|
||||
it('Should deprovision a resource', async function () {
|
||||
await contract.provisionResource(
|
||||
'resource-001',
|
||||
'us-east-1',
|
||||
'datacenter-1',
|
||||
0,
|
||||
'{}'
|
||||
)
|
||||
|
||||
const tx = await contract.deprovisionResource('resource-001')
|
||||
await expect(tx).to.emit(contract, 'ResourceDeprovisioned')
|
||||
|
||||
const resource = await contract.getResource('resource-001')
|
||||
expect(resource.active).to.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user