sharding/contract: merge with master

Former-commit-id: 9f271cd21ed6c7c5b3b04a9db7118d2a75f61d34 [formerly 2dc1d365b337c98aa543b6d6e8b54bf0b92d48c1]
Former-commit-id: ebaf4132fbbd00b027dacd4b9e38f2f765274b70
This commit is contained in:
Terence Tsao 2018-05-15 11:22:38 -07:00
commit 89dedc3184
5 changed files with 62 additions and 27 deletions

View File

@ -83,7 +83,7 @@ Casper Proof of Stake (Casper [FFG](https://arxiv.org/abs/1710.09437) and [CBC](
In practice, the first phase of sharding will not be a complete overhaul of the network, but rather an implementation through a smart contract on the main chain known as the **Sharding Manager Contract (SMC)**. Its responsibility is to manage submitted collation headers and manage notaries.
Among its basic responsibilities, the SMC is be responsible for reconciling notaries across all shards. It is in charge of pseudorandomly sampling notaries from addresses that have staked ETH into the SMC. The SMC is also responsible for providing immediate collation header verification that records a valid collation header hash on the main chain. In essence, sharding revolves around being able to store collation headers and their associated votes in the main chain through this smart contract.
Among its basic responsibilities, the SMC is responsible for reconciling notaries across all shards. It is in charge of pseudorandomly sampling notaries from addresses that have staked ETH into the SMC. The SMC is also responsible for providing immediate collation header verification that records a valid collation header hash on the main chain. In essence, sharding revolves around being able to store collation headers and their associated votes in the main chain through this smart contract.
# Roadmap Phases

File diff suppressed because one or more lines are too long

View File

@ -70,9 +70,11 @@ contract SMC {
/// Checks if a notary with given shard id and period has been chosen as
/// a committee member to vote for header added on to the main chain
function getNotaryInCommittee(uint _shardId, uint _index) public view returns(address) {
function getNotaryInCommittee(uint _shardId) public view returns(address) {
uint period = block.number / PERIOD_LENGTH;
updateNotarySampleSize();
// Determine notary pool length based on notary sample size
uint sampleSize;
if (period > sampleSizeLastUpdatedPeriod) {
@ -81,10 +83,13 @@ contract SMC {
sampleSize = currentPeriodNotarySampleSize;
}
// Get the most recent block number before the period started
// Get the notary pool index to concatenate with shardId and blockHash for random sample
uint poolIndex = notaryRegistry[msg.sender].poolIndex;
// Get the most recent block number before the period started
uint latestBlock = period * PERIOD_LENGTH - 1;
uint latestBlockHash = uint(block.blockhash(latestBlock));
uint index = uint(keccak256(latestBlockHash, _index, _shardId)) % sampleSize;
uint index = uint(keccak256(latestBlockHash, poolIndex, _shardId)) % sampleSize;
return notaryPool[index];
}
@ -197,7 +202,7 @@ contract SMC {
require(_chunkRoot == collationRecords[_shardId][_period].chunkRoot);
require(notaryRegistry[msg.sender].deposited);
require(!hasVoted(_shardId, _index));
require(getNotaryInCommittee(_shardId, _index) == msg.sender);
require(getNotaryInCommittee(_shardId) == msg.sender);
castVote(_shardId, _index);
uint voteCount = getVoteCount(_shardId);

View File

@ -463,8 +463,8 @@ func TestCommitteeListsAreDifferent(t *testing.T) {
// Compare sampled first 5 notaries of shard 0 to shard 1, they should not be identical.
for i := 0; i < 5; i++ {
addr0, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0), big.NewInt(int64(i)))
addr1, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(1), big.NewInt(int64(i)))
addr0, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
addr1, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(1))
if addr0 == addr1 {
t.Errorf("Shard 0 committee list is identical to shard 1's committee list")
}
@ -508,7 +508,7 @@ func TestGetCommitteeWithNonMember(t *testing.T) {
// Verify the unregistered account is not in the notary pool list.
for i := 0; i < 10; i++ {
addr, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0), big.NewInt(int64(i)))
addr, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
if notaryPoolAddr[10].String() == addr.String() {
t.Errorf("Account %s is not a notary", notaryPoolAddr[10].String())
}
@ -516,6 +516,37 @@ func TestGetCommitteeWithNonMember(t *testing.T) {
}
// TestGetCommitteeWithinSamePeriod tests notary registers and samples within the same period
func TestGetCommitteeWithinSamePeriod(t *testing.T) {
addr := crypto.PubkeyToAddress(mainKey.PublicKey)
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance2000Eth}})
txOpts := bind.NewKeyedTransactor(mainKey)
txOpts.Value = notaryDeposit
_, _, smc, _ := deploySMCContract(backend, mainKey)
// Notary 0 registers.
smc.RegisterNotary(txOpts)
backend.Commit()
notary, _ := smc.NotaryRegistry(&bind.CallOpts{}, addr)
numNotaries, _ := smc.NotaryPoolLength(&bind.CallOpts{})
if !notary.Deposited {
t.Errorf("Notary has not registered. Got deposited flag: %v", notary.Deposited)
}
if numNotaries.Cmp(big.NewInt(1)) != 0 {
t.Errorf("Incorrect count from notary pool. Want: 1, Got: %v", numNotaries)
}
// Notary 0 samples for itself within the same period after registration
sampledAddr, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
if addr != sampledAddr {
t.Errorf("Unable to sample notary address within same period of registration, got addr: %v", sampledAddr)
}
}
// TestGetCommitteeAfterDeregisters tests notary tries to be in committee after deregistered.
func TestGetCommitteeAfterDeregisters(t *testing.T) {
const notaryCount = 10
@ -562,7 +593,7 @@ func TestGetCommitteeAfterDeregisters(t *testing.T) {
// Verify degistered notary 0 is not in the notary pool list.
for i := 0; i < 10; i++ {
addr, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0), big.NewInt(int64(i)))
addr, _ := smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
if notaryPoolAddr[0].String() == addr.String() {
t.Errorf("Account %s is not a notary", notaryPoolAddr[0].String())
}

View File

@ -57,10 +57,9 @@ func subscribeBlockHeaders(c client.Client) error {
// conditions are met.
func checkSMCForNotary(c client.Client, head *types.Header) error {
log.Info("Checking if we are an eligible collation notary for a shard...")
period := big.NewInt(0).Div(head.Number, big.NewInt(sharding.PeriodLength))
for s := int64(0); s < sharding.ShardCount; s++ {
// Checks if we are an eligible notary according to the SMC.
addr, err := c.SMCCaller().GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(s), period)
addr, err := c.SMCCaller().GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(s))
if err != nil {
return err
@ -74,9 +73,9 @@ func checkSMCForNotary(c client.Client, head *types.Header) error {
return err
}
// If the account is selected as collator, submit collation.
// If the account is selected as notary, submit collation.
if addr == c.Account().Address {
log.Info(fmt.Sprintf("Selected as collator on shard: %d", s))
log.Info(fmt.Sprintf("Selected as notary on shard: %d", s))
err := submitCollation(s)
if err != nil {
return fmt.Errorf("could not add collation. %v", err)