mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Merge branch 'smc_phase1' of https://github.com/enriquefynn/go-ethereum into smc_phase1.1
Former-commit-id: 514310116906d0e4531bd714d4b38256f6da8f3f [formerly e68690130b4d0f0547c168b3ccff41c012669f96] Former-commit-id: 601235a7b4929b74faadd5e237017c7da5e1eea5
This commit is contained in:
@@ -1,35 +1,44 @@
|
||||
pragma solidity ^0.4.19;
|
||||
|
||||
contract SMC {
|
||||
event TxToShard(address indexed to, int indexed shardId, int receiptId);
|
||||
event CollationAdded(int indexed shardId, uint expectedPeriodNumber,
|
||||
bytes32 periodStartPrevHash, bytes32 parentHash,
|
||||
bytes32 transactionRoot, address coinbase,
|
||||
bytes32 stateRoot, bytes32 receiptRoot,
|
||||
int number, bool isNewHead, int score);
|
||||
event Deposit(address collator, int index);
|
||||
event Withdraw(int index);
|
||||
event HeaderAdded(uint indexed shard_id, bytes32 parent_hash,
|
||||
bytes32 chunk_root, int128 period, int128 height,
|
||||
address proposer_address, uint proposer_bid,
|
||||
bytes proposer_signature);
|
||||
event CollatorRegistered(address collator, uint pool_index);
|
||||
event CollatorDeregistered(uint pool_index);
|
||||
event CollatorReleased(uint pool_index);
|
||||
event ProposerRegistered(uint pool_index);
|
||||
event ProposerDeregistered(uint index);
|
||||
event ProposerReleased(uint index);
|
||||
|
||||
// Entry in collator_registry
|
||||
struct Collator {
|
||||
// Amount of wei the collator holds
|
||||
uint deposit;
|
||||
// The collator's address
|
||||
address addr;
|
||||
// When collator asked for unregistration
|
||||
uint deregistered;
|
||||
// The collator's pool index
|
||||
uint pool_index;
|
||||
// False if collator has not deposited, true otherwise
|
||||
bool deposited;
|
||||
}
|
||||
|
||||
// Entry in proposer_registry
|
||||
struct Proposer {
|
||||
// Shard id of the deposit
|
||||
uint shardId;
|
||||
// Deposit in ether in each shard
|
||||
uint[] deposit;
|
||||
}
|
||||
|
||||
struct CollationHeader {
|
||||
bytes32 parentHash;
|
||||
int score;
|
||||
}
|
||||
|
||||
struct Receipt {
|
||||
int shardId;
|
||||
uint txStartgas;
|
||||
uint txGasprice;
|
||||
uint value;
|
||||
bytes32 data;
|
||||
address sender;
|
||||
address to;
|
||||
uint256 shard_id; // pointer to shard
|
||||
bytes32 parent_hash; // pointer to parent header
|
||||
bytes32 chunk_root; // pointer to collation body
|
||||
int128 period; // Period which header should be included
|
||||
int128 height; // Collation's height
|
||||
address proposer_address; // Proposer's address
|
||||
uint256 proposer_bid; // Proposer's bid
|
||||
bytes proposer_signature; // Proposer's signature
|
||||
}
|
||||
|
||||
// Packed variables to be used in addHeader
|
||||
@@ -41,213 +50,239 @@ contract SMC {
|
||||
}
|
||||
|
||||
// collatorId => Collators
|
||||
mapping (int => Collator) public collators;
|
||||
// mapping (int => Collator) public collators;
|
||||
address[] public collator_pool;
|
||||
// proposerId => Proposer
|
||||
// mapping (int => Proposer) public proposers;
|
||||
Proposer[] public proposer_pool;
|
||||
|
||||
// Collator registry (deregistered is 0 for not yet deregistered collators)
|
||||
mapping (address => Collator) public collator_registry;
|
||||
mapping (address => Proposer) public proposer_registry;
|
||||
// shard_id => (header_hash => tree root)
|
||||
mapping (uint => mapping (bytes32 => bytes32)) public collation_trees;
|
||||
// shardId => (headerHash => CollationHeader)
|
||||
mapping (int => mapping (bytes32 => CollationHeader)) public collationHeaders;
|
||||
// receiptId => Receipt
|
||||
mapping (int => Receipt) public receipts;
|
||||
// shardId => headerHash
|
||||
mapping (int => bytes32) shardHead;
|
||||
mapping (int => bytes32) shardead;
|
||||
|
||||
// Number of collators
|
||||
int public numCollators;
|
||||
// Number of receipts
|
||||
int numReceipts;
|
||||
// Indexs of empty slots caused by the function `withdraw`
|
||||
mapping (int => int) emptySlotsStack;
|
||||
uint public collator_pool_len;
|
||||
// Indexes of empty slots caused by the function `withdraw`
|
||||
uint[] empty_slots_stack;
|
||||
// The top index of the stack in empty_slots_stack
|
||||
int emptySlotsStackTop;
|
||||
// Has the collator deposited before?
|
||||
mapping (address => bool) public isCollatorDeposited;
|
||||
uint empty_slots_stack_top;
|
||||
|
||||
// Constant values
|
||||
uint constant periodLength = 5;
|
||||
int constant public shardCount = 100;
|
||||
// The exact deposit size which you have to deposit to become a collator
|
||||
uint constant depositSize = 1000 ether;
|
||||
uint constant PERIOD_LENGTH = 5;
|
||||
// Exact collation body size (1mb)
|
||||
uint constant COLLATION_SIZE = 2 ** 20;
|
||||
// Subsidy in vEth
|
||||
uint constant COLLATOR_SUBSIDY = 0.001 ether;
|
||||
// Number of shards
|
||||
uint constant SHARD_COUNT = 100;
|
||||
// The minimum deposit size for a collator
|
||||
uint constant COLLATOR_DEPOSIT = 1000 ether;
|
||||
// The minimum deposit size for a proposer
|
||||
uint constant PROPOSER_DEPOSIT = 1 ether;
|
||||
// The minimum balance of a proposer (for collators)
|
||||
uint constant MIN_PROPOSER_BALANCE = 0.1 ether;
|
||||
// Time the ether is locked by collators (Not constant for testing)
|
||||
uint COLLATOR_LOCKUP_LENGTH = 16128;
|
||||
// Time the ether is locked by proposers (Not constant for testing)
|
||||
uint PROPOSER_LOCKUP_LENGTH = 48;
|
||||
// Number of periods ahead of current period, which the contract
|
||||
// is able to return the collator of that period
|
||||
uint constant lookAheadPeriods = 4;
|
||||
uint constant LOOKAHEAD_LENGTH = 4;
|
||||
|
||||
// Log the latest period number of the shard
|
||||
mapping (int => int) public periodHead;
|
||||
mapping (int => int) public period_head;
|
||||
|
||||
function SMC() public {
|
||||
}
|
||||
|
||||
// Returns the gas limit that collations can currently have (by default make
|
||||
// this function always answer 10 million).
|
||||
function getCollationGasLimit() public pure returns(uint) {
|
||||
return 10000000;
|
||||
function SMC(uint collator_lockup_length, uint proposer_lockup_length) public {
|
||||
COLLATOR_LOCKUP_LENGTH = collator_lockup_length;
|
||||
PROPOSER_LOCKUP_LENGTH = proposer_lockup_length;
|
||||
}
|
||||
|
||||
event LOG(uint L);
|
||||
// Uses a block hash as a seed to pseudorandomly select a signer from the collator pool.
|
||||
// [TODO] Chance of being selected should be proportional to the collator's deposit.
|
||||
// Should be able to return a value for the current period or any future period up to.
|
||||
function getEligibleCollator(int _shardId, uint _period) public view returns(address) {
|
||||
require(_period >= lookAheadPeriods);
|
||||
require((_period - lookAheadPeriods) * periodLength < block.number);
|
||||
require(numCollators > 0);
|
||||
// [TODO] Should check further if this safe or not
|
||||
return collators[
|
||||
int(
|
||||
uint(
|
||||
keccak256(
|
||||
uint(block.blockhash((_period - lookAheadPeriods) * periodLength)),
|
||||
_shardId
|
||||
)
|
||||
) %
|
||||
uint(getCollatorsMaxIndex())
|
||||
function get_eligible_collator(uint shard_id, uint period) public view returns(address) {
|
||||
uint current_period = block.number / PERIOD_LENGTH;
|
||||
uint period_to_look = ((period - LOOKAHEAD_LENGTH) * PERIOD_LENGTH);
|
||||
require(period >= current_period);
|
||||
require(period <= (current_period + LOOKAHEAD_LENGTH));
|
||||
require(collator_pool_len > 0);
|
||||
if (period <= LOOKAHEAD_LENGTH)
|
||||
period_to_look = period;
|
||||
require(period_to_look < block.number);
|
||||
return collator_pool[uint(
|
||||
keccak256(
|
||||
block.blockhash(period_to_look),
|
||||
shard_id
|
||||
)
|
||||
].addr;
|
||||
) %
|
||||
collator_pool_len
|
||||
];
|
||||
}
|
||||
|
||||
function deposit() public payable returns(int) {
|
||||
require(!isCollatorDeposited[msg.sender]);
|
||||
require(msg.value == depositSize);
|
||||
// Find the empty slot index in collators pool
|
||||
int index;
|
||||
if (!isStackEmpty())
|
||||
index = stackPop();
|
||||
else
|
||||
index = int(numCollators);
|
||||
function compute_header_hash(uint256 shard_id,
|
||||
bytes32 parent_hash,
|
||||
bytes32 chunk_root,
|
||||
uint256 period,
|
||||
address proposer_address,
|
||||
uint256 proposer_bid) public returns(bytes32){
|
||||
|
||||
collators[index] = Collator({
|
||||
deposit: msg.value,
|
||||
addr: msg.sender
|
||||
}
|
||||
|
||||
function register_collator() public payable returns(bool) {
|
||||
address collator_address = msg.sender;
|
||||
require(!collator_registry[collator_address].deposited);
|
||||
require(msg.value == COLLATOR_DEPOSIT);
|
||||
|
||||
uint index;
|
||||
if (!empty_stack()) {
|
||||
index = stack_pop();
|
||||
collator_pool[index] = collator_address;
|
||||
}
|
||||
else {
|
||||
index = collator_pool_len;
|
||||
collator_pool.push(collator_address);
|
||||
}
|
||||
++collator_pool_len;
|
||||
|
||||
collator_registry[collator_address] = Collator({
|
||||
deregistered: 0,
|
||||
pool_index: index,
|
||||
deposited: true
|
||||
});
|
||||
++numCollators;
|
||||
isCollatorDeposited[msg.sender] = true;
|
||||
|
||||
Deposit(msg.sender, index);
|
||||
return index;
|
||||
CollatorRegistered(collator_address, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes the collator from the collator pool and refunds the deposited ether
|
||||
function withdraw(int _collatorIndex) public {
|
||||
require(msg.sender == collators[_collatorIndex].addr);
|
||||
// [FIXME] Should consider calling the collator's contract, might be useful
|
||||
// when the collator is a contract.
|
||||
collators[_collatorIndex].addr.transfer(collators[_collatorIndex].deposit);
|
||||
isCollatorDeposited[collators[_collatorIndex].addr] = false;
|
||||
delete collators[_collatorIndex];
|
||||
stackPush(_collatorIndex);
|
||||
--numCollators;
|
||||
Withdraw(_collatorIndex);
|
||||
// Removes the collator from the collator pool and sets deregistered period
|
||||
function deregister_collator() public {
|
||||
address collator_address = msg.sender;
|
||||
uint index = collator_registry[collator_address].pool_index;
|
||||
// Check if collator deposited
|
||||
require(collator_registry[collator_address].deposited);
|
||||
require(collator_pool[index] == collator_address);
|
||||
|
||||
// Deregistered period
|
||||
collator_registry[collator_address].deregistered = block.number / PERIOD_LENGTH;
|
||||
|
||||
stack_push(index);
|
||||
--collator_pool_len;
|
||||
CollatorDeregistered(index);
|
||||
}
|
||||
|
||||
function release_collator() public {
|
||||
address collator_address = msg.sender;
|
||||
require(collator_registry[collator_address].deposited == true);
|
||||
// Deregistered
|
||||
require(collator_registry[collator_address].deregistered != 0);
|
||||
// Locked up period
|
||||
require((block.number / PERIOD_LENGTH) > (collator_registry[collator_address].deregistered + COLLATOR_LOCKUP_LENGTH));
|
||||
|
||||
delete collator_registry[collator_address];
|
||||
collator_address.transfer(COLLATOR_DEPOSIT);
|
||||
}
|
||||
|
||||
function register_proposer() public payable returns(int) {
|
||||
|
||||
}
|
||||
|
||||
function deregister_proposer() public {
|
||||
|
||||
}
|
||||
|
||||
function release_proposer() public {
|
||||
|
||||
}
|
||||
|
||||
function proposer_add_balance(uint shard_id) payable public {
|
||||
|
||||
}
|
||||
|
||||
function proposer_withdraw_balance(uint shard_id) public {
|
||||
|
||||
}
|
||||
|
||||
// Attempts to process a collation header, returns true on success, reverts on failure.
|
||||
function addHeader(int _shardId, uint _expectedPeriodNumber, bytes32 _periodStartPrevHash,
|
||||
bytes32 _parentHash, bytes32 _transactionRoot,
|
||||
address _coinbase, bytes32 _stateRoot, bytes32 _receiptRoot,
|
||||
int _number) public returns(bool) {
|
||||
HeaderVars memory headerVars;
|
||||
function addHeader(uint _shardId, uint period, bytes32 height,
|
||||
bytes32 _parent_hash, bytes32 chunk_root,
|
||||
address proposer_address, uint proposer_bid,
|
||||
bytes proposer_signature) public returns(bool) {
|
||||
// HeaderVars memory headerVars;
|
||||
|
||||
// Check if the header is valid
|
||||
require((_shardId >= 0) && (_shardId < shardCount));
|
||||
require(block.number >= periodLength);
|
||||
require(_expectedPeriodNumber == block.number / periodLength);
|
||||
require(_periodStartPrevHash == block.blockhash(_expectedPeriodNumber * periodLength - 1));
|
||||
// // Check if the header is valid
|
||||
// require((_shardId >= 0) && (_shardId < shardCount));
|
||||
// require(block.number >= periodLength);
|
||||
// require(_expectedPeriodNumber == block.number / periodLength);
|
||||
// require(_periodStartPrevHash == block.blockhash(_expectedPeriodNumber * periodLength - 1));
|
||||
|
||||
// Check if this header already exists
|
||||
headerVars.entireHeaderHash = keccak256(_shardId, _expectedPeriodNumber, _periodStartPrevHash,
|
||||
_parentHash, _transactionRoot, bytes32(_coinbase),
|
||||
_stateRoot, _receiptRoot, _number);
|
||||
assert(collationHeaders[_shardId][headerVars.entireHeaderHash].score == 0);
|
||||
// Check whether the parent exists.
|
||||
// if (parent_collation_hash == 0), i.e., is the genesis,
|
||||
// then there is no need to check.
|
||||
if (_parentHash != 0x0)
|
||||
assert(collationHeaders[_shardId][_parentHash].score > 0);
|
||||
// Check if only one collation in one period
|
||||
assert(periodHead[_shardId] < int(_expectedPeriodNumber));
|
||||
// // Check if this header already exists
|
||||
// headerVars.entireHeaderHash = keccak256(_shardId, _expectedPeriodNumber, _periodStartPrevHash,
|
||||
// _parentHash, _transactionRoot, bytes32(_coinbase),
|
||||
// _stateRoot, _receiptRoot, _number);
|
||||
// assert(collationHeaders[_shardId][headerVars.entireHeaderHash].score == 0);
|
||||
// // Check whether the parent exists.
|
||||
// // if (parent_collation_hash == 0), i.e., is the genesis,
|
||||
// // then there is no need to check.
|
||||
// if (_parentHash != 0x0)
|
||||
// assert(collationHeaders[_shardId][_parentHash].score > 0);
|
||||
// // Check if only one collation in one period
|
||||
// assert(periodHead[_shardId] < int(_expectedPeriodNumber));
|
||||
|
||||
// Check the signature with validation_code_addr
|
||||
headerVars.collatorAddr = getEligibleCollator(_shardId, block.number/periodLength);
|
||||
require(headerVars.collatorAddr != 0x0);
|
||||
require(msg.sender == headerVars.collatorAddr);
|
||||
// // Check the signature with validation_code_addr
|
||||
// headerVars.collatorAddr = getEligibleCollator(_shardId, block.number/periodLength);
|
||||
// require(headerVars.collatorAddr != 0x0);
|
||||
// require(msg.sender == headerVars.collatorAddr);
|
||||
|
||||
// Check score == collationNumber
|
||||
headerVars.score = collationHeaders[_shardId][_parentHash].score + 1;
|
||||
require(_number == headerVars.score);
|
||||
// // Check score == collationNumber
|
||||
// headerVars.score = collationHeaders[_shardId][_parentHash].score + 1;
|
||||
// require(_number == headerVars.score);
|
||||
|
||||
// Add the header
|
||||
collationHeaders[_shardId][headerVars.entireHeaderHash] = CollationHeader({
|
||||
parentHash: _parentHash,
|
||||
score: headerVars.score
|
||||
});
|
||||
// // Add the header
|
||||
// collationHeaders[_shardId][headerVars.entireHeaderHash] = CollationHeader({
|
||||
// parentHash: _parentHash,
|
||||
// score: headerVars.score
|
||||
// });
|
||||
|
||||
// Update the latest period number
|
||||
periodHead[_shardId] = int(_expectedPeriodNumber);
|
||||
// // Update the latest period number
|
||||
// periodHead[_shardId] = int(_expectedPeriodNumber);
|
||||
|
||||
// Determine the head
|
||||
if (headerVars.score > collationHeaders[_shardId][shardHead[_shardId]].score) {
|
||||
shardHead[_shardId] = headerVars.entireHeaderHash;
|
||||
headerVars.isNewHead = true;
|
||||
}
|
||||
// // Determine the head
|
||||
// if (headerVars.score > collationHeaders[_shardId][shardHead[_shardId]].score) {
|
||||
// shardHead[_shardId] = headerVars.entireHeaderHash;
|
||||
// headerVars.isNewHead = true;
|
||||
// }
|
||||
|
||||
CollationAdded(_shardId, _expectedPeriodNumber, _periodStartPrevHash,
|
||||
_parentHash, _transactionRoot, _coinbase, _stateRoot,
|
||||
_receiptRoot, _number, headerVars.isNewHead, headerVars.score);
|
||||
// CollationAdded(_shardId, _expectedPeriodNumber, _periodStartPrevHash,
|
||||
// _parentHash, _transactionRoot, _coinbase, _stateRoot,
|
||||
// _receiptRoot, _number, headerVars.isNewHead, headerVars.score);
|
||||
|
||||
return true;
|
||||
// return true;
|
||||
}
|
||||
|
||||
// Records a request to deposit msg.value ETH to address to in shard shard_id
|
||||
// during a future collation. Saves a `receipt ID` for this request,
|
||||
// also saving `msg.sender`, `msg.value`, `to`, `shard_id`, `startgas`,
|
||||
// `gasprice`, and `data`.
|
||||
function txToShard(address _to, int _shardId, uint _txStartgas, uint _txGasprice,
|
||||
bytes12 _data) public payable returns(int) {
|
||||
receipts[numReceipts] = Receipt({
|
||||
shardId: _shardId,
|
||||
txStartgas: _txStartgas,
|
||||
txGasprice: _txGasprice,
|
||||
value: msg.value,
|
||||
sender: msg.sender,
|
||||
to: _to,
|
||||
data: _data
|
||||
});
|
||||
var receiptId = numReceipts;
|
||||
++numReceipts;
|
||||
|
||||
TxToShard(_to, _shardId, receiptId);
|
||||
return receiptId;
|
||||
function empty_stack() internal view returns(bool) {
|
||||
return empty_slots_stack_top == 0;
|
||||
}
|
||||
|
||||
function updateGasPrice(int _receiptId, uint _txGasprice) public payable returns(bool) {
|
||||
require(receipts[_receiptId].sender == msg.sender);
|
||||
receipts[_receiptId].txGasprice = _txGasprice;
|
||||
return true;
|
||||
function stack_push(uint index) internal {
|
||||
if (empty_slots_stack.length == empty_slots_stack_top)
|
||||
empty_slots_stack.push(index);
|
||||
else
|
||||
empty_slots_stack[empty_slots_stack_top] = index;
|
||||
|
||||
++empty_slots_stack_top;
|
||||
}
|
||||
|
||||
function isStackEmpty() internal view returns(bool) {
|
||||
return emptySlotsStackTop == 0;
|
||||
}
|
||||
|
||||
function stackPush(int index) internal {
|
||||
emptySlotsStack[emptySlotsStackTop] = index;
|
||||
++emptySlotsStackTop;
|
||||
}
|
||||
|
||||
function stackPop() internal returns(int) {
|
||||
if (isStackEmpty())
|
||||
return -1;
|
||||
--emptySlotsStackTop;
|
||||
return emptySlotsStack[emptySlotsStackTop];
|
||||
}
|
||||
|
||||
function getCollatorsMaxIndex() internal view returns(int) {
|
||||
int activateCollatorNum = 0;
|
||||
int allCollatorSlotsNum = numCollators + emptySlotsStackTop;
|
||||
|
||||
// TODO: any better way to iterate the mapping?
|
||||
for (int i = 0; i < 1024; ++i) {
|
||||
if (i >= allCollatorSlotsNum)
|
||||
break;
|
||||
if (collators[i].addr != 0x0)
|
||||
activateCollatorNum += 1;
|
||||
}
|
||||
return activateCollatorNum + emptySlotsStackTop;
|
||||
// Pop element from stack
|
||||
// Caller should check if stack is empty
|
||||
function stack_pop() internal returns(uint) {
|
||||
require(empty_slots_stack_top > 1);
|
||||
--empty_slots_stack_top;
|
||||
return empty_slots_stack[empty_slots_stack_top];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package contracts
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
@@ -12,80 +13,74 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
type SMCConfig struct {
|
||||
collatorLockupLenght *big.Int
|
||||
proposerLockupLength *big.Int
|
||||
}
|
||||
|
||||
var (
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
mainKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
accountBalance1001Eth, _ = new(big.Int).SetString("1001000000000000000000", 10)
|
||||
collatorDeposit, _ = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
smcConfig = SMCConfig{
|
||||
collatorLockupLenght: new(big.Int).SetInt64(1),
|
||||
proposerLockupLength: new(big.Int).SetInt64(1),
|
||||
}
|
||||
)
|
||||
|
||||
func deploySMCContract(backend *backends.SimulatedBackend) (common.Address, *types.Transaction, *SMC, error) {
|
||||
func deploySMCContract(backend *backends.SimulatedBackend, key *ecdsa.PrivateKey) (common.Address, *types.Transaction, *SMC, error) {
|
||||
transactOpts := bind.NewKeyedTransactor(key)
|
||||
defer backend.Commit()
|
||||
return DeploySMC(transactOpts, backend)
|
||||
return DeploySMC(transactOpts, backend, smcConfig.collatorLockupLenght, smcConfig.proposerLockupLength)
|
||||
}
|
||||
|
||||
// Test creating the SMC contract
|
||||
func TestContractCreation(t *testing.T) {
|
||||
addr := crypto.PubkeyToAddress(mainKey.PublicKey)
|
||||
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance1001Eth}})
|
||||
_, _, _, err := deploySMCContract(backend)
|
||||
_, _, _, err := deploySMCContract(backend, mainKey)
|
||||
backend.Commit()
|
||||
if err != nil {
|
||||
t.Fatalf("can't deploy SMC: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test getting the collation gas limit
|
||||
func TestGetCollationGasLimit(t *testing.T) {
|
||||
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance1001Eth}})
|
||||
_, _, smc, _ := deploySMCContract(backend)
|
||||
gasLimit, err := smc.GetCollationGasLimit(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting collationGasLimit: %v", err)
|
||||
}
|
||||
if gasLimit.Cmp(big.NewInt(10000000)) != 0 {
|
||||
t.Fatalf("collation gas limit should be 10000000 gas")
|
||||
}
|
||||
}
|
||||
|
||||
// Test collator deposit
|
||||
// Test register collator
|
||||
func TestCollatorDeposit(t *testing.T) {
|
||||
addr := crypto.PubkeyToAddress(mainKey.PublicKey)
|
||||
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance1001Eth}})
|
||||
transactOpts := bind.NewKeyedTransactor(key)
|
||||
_, _, smc, _ := deploySMCContract(backend)
|
||||
transactOpts := bind.NewKeyedTransactor(mainKey)
|
||||
_, _, smc, _ := deploySMCContract(backend, mainKey)
|
||||
|
||||
// Test deposit() function
|
||||
// Deposit 100 Eth
|
||||
// Test register_collator() function
|
||||
// Deposit 1000 Eth
|
||||
transactOpts.Value = collatorDeposit
|
||||
|
||||
if _, err := smc.Deposit(transactOpts); err != nil {
|
||||
if _, err := smc.Register_collator(transactOpts); err != nil {
|
||||
t.Fatalf("Collator cannot deposit: %v", err)
|
||||
}
|
||||
backend.Commit()
|
||||
|
||||
// Check updated number of collators
|
||||
numCollators, err := smc.NumCollators(&bind.CallOpts{})
|
||||
numCollators, err := smc.Collator_pool_len(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get number of collators: %v", err)
|
||||
t.Fatalf("Failed to get collator pool length: %v", err)
|
||||
}
|
||||
if numCollators.Cmp(big.NewInt(1)) != 0 {
|
||||
t.Fatalf("Failed to update number of collators")
|
||||
}
|
||||
|
||||
// Check collator structure
|
||||
collatorStruct, err := smc.Collators(&bind.CallOpts{}, big.NewInt(0))
|
||||
// Check deposited is true
|
||||
tx, err := smc.Collator_registry(&bind.CallOpts{}, addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get collator structure: %v", err)
|
||||
t.Fatalf("Failed to update collator registry: %v", err)
|
||||
}
|
||||
if collatorStruct.Addr != addr {
|
||||
t.Fatalf("Wrong collator address, %v should be %v", collatorStruct.Addr, addr)
|
||||
}
|
||||
if collatorStruct.Deposit.Cmp(collatorDeposit) != 0 {
|
||||
t.Fatalf("Wrong collator deposit, %v should be %v", collatorStruct.Deposit, collatorDeposit)
|
||||
if tx.Deposited != true {
|
||||
t.Fatalf("Collator registry not updated")
|
||||
}
|
||||
|
||||
// Check for the Deposit event
|
||||
depositsEventsIterator, err := smc.FilterDeposit(&bind.FilterOpts{})
|
||||
// Check for the RegisterCollator event
|
||||
depositsEventsIterator, err := smc.FilterCollatorRegistered(&bind.FilterOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get Deposit event: %v", err)
|
||||
}
|
||||
@@ -95,36 +90,85 @@ func TestCollatorDeposit(t *testing.T) {
|
||||
if depositsEventsIterator.Event.Collator != addr {
|
||||
t.Fatalf("Collator address mismatch: %x should be %x", depositsEventsIterator.Event.Collator, addr)
|
||||
}
|
||||
if depositsEventsIterator.Event.Index.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Fatalf("Collator index mismatch: %d should be 0", depositsEventsIterator.Event.Index)
|
||||
if depositsEventsIterator.Event.Pool_index.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Fatalf("Collator index mismatch: %d should be 0", depositsEventsIterator.Event.Pool_index)
|
||||
}
|
||||
}
|
||||
|
||||
// Test collator withdraw
|
||||
func TestCollatorWithdraw(t *testing.T) {
|
||||
// Test collator deregister from pool
|
||||
func TestCollatorDeregister(t *testing.T) {
|
||||
addr := crypto.PubkeyToAddress(mainKey.PublicKey)
|
||||
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance1001Eth}})
|
||||
transactOpts := bind.NewKeyedTransactor(key)
|
||||
_, _, smc, _ := deploySMCContract(backend)
|
||||
transactOpts := bind.NewKeyedTransactor(mainKey)
|
||||
_, _, smc, _ := deploySMCContract(backend, mainKey)
|
||||
|
||||
transactOpts.Value = collatorDeposit
|
||||
smc.Deposit(transactOpts)
|
||||
// Register collator
|
||||
smc.Register_collator(transactOpts)
|
||||
|
||||
transactOpts.Value = big.NewInt(0)
|
||||
_, err := smc.Withdraw(transactOpts, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to withdraw: %v", err)
|
||||
}
|
||||
// Deregister collator
|
||||
_, err := smc.Deregister_collator(transactOpts)
|
||||
backend.Commit()
|
||||
|
||||
// Check for the Withdraw event
|
||||
withdrawsEventsIterator, err := smc.FilterWithdraw(&bind.FilterOpts{Start: 0})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get withdraw event: %v", err)
|
||||
t.Fatalf("Failed to deregister collator: %v", err)
|
||||
}
|
||||
|
||||
// Check for the CollatorDeregistered event
|
||||
withdrawsEventsIterator, err := smc.FilterCollatorDeregistered(&bind.FilterOpts{Start: 0})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get CollatorDeregistered event: %v", err)
|
||||
}
|
||||
if !withdrawsEventsIterator.Next() {
|
||||
t.Fatal("No withdraw event found")
|
||||
t.Fatal("No CollatorDeregistered event found")
|
||||
}
|
||||
if withdrawsEventsIterator.Event.Index.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Fatalf("Collator index mismatch: %d should be 0", withdrawsEventsIterator.Event.Index)
|
||||
if withdrawsEventsIterator.Event.Pool_index.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Fatalf("Collator index mismatch: %d should be 0", withdrawsEventsIterator.Event.Pool_index)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEligibleCollator(t *testing.T) {
|
||||
const numberCollators = 20
|
||||
var collatorPoolAddr [numberCollators]common.Address
|
||||
var collatorPoolPrivKeys [numberCollators]*ecdsa.PrivateKey
|
||||
var transactOpts [numberCollators]*bind.TransactOpts
|
||||
genesis := make(core.GenesisAlloc)
|
||||
|
||||
for i := 0; i < numberCollators; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
collatorPoolPrivKeys[i] = key
|
||||
collatorPoolAddr[i] = crypto.PubkeyToAddress(key.PublicKey)
|
||||
transactOpts[i] = bind.NewKeyedTransactor(key)
|
||||
transactOpts[i].Value = collatorDeposit
|
||||
|
||||
genesis[collatorPoolAddr[i]] = core.GenesisAccount{
|
||||
Balance: accountBalance1001Eth,
|
||||
}
|
||||
}
|
||||
|
||||
backend := backends.NewSimulatedBackend(genesis)
|
||||
_, _, smc, _ := deploySMCContract(backend, collatorPoolPrivKeys[0])
|
||||
|
||||
// Register collator
|
||||
for i := 0; i < numberCollators; i++ {
|
||||
smc.Register_collator(transactOpts[i])
|
||||
}
|
||||
|
||||
// Move blockchain 4 blocks further (Head is at 5 after) : period 1
|
||||
for i := 0; i < 4; i++ {
|
||||
backend.Commit()
|
||||
}
|
||||
|
||||
_, err := smc.Get_eligible_collator(&bind.CallOpts{}, big.NewInt(0), big.NewInt(4))
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot get eligible collator: %v", err)
|
||||
}
|
||||
// after: Head is 11, period 2
|
||||
for i := 0; i < 6; i++ {
|
||||
backend.Commit()
|
||||
}
|
||||
_, err = smc.Get_eligible_collator(&bind.CallOpts{}, big.NewInt(1), big.NewInt(6))
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot get eligible collator: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user