mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
client: Change Notary to Attester Across Codebase (#326)
This commit is contained in:
committed by
Raul Jordan
parent
09ca832a5f
commit
2bd1e334bc
@@ -96,21 +96,21 @@ Build our system first
|
||||
$ bazel build //client/...
|
||||
```
|
||||
|
||||
## Becoming a Notary
|
||||
## Becoming a Attester
|
||||
|
||||
|
||||
Make sure a geth node is running as a separate process. Then, to deposit ETH and join as a notary in the Sharding Manager Contract, run the following command:
|
||||
Make sure a geth node is running as a separate process. Then, to deposit ETH and join as a attester in the Sharding Manager Contract, run the following command:
|
||||
|
||||
```
|
||||
bazel run //client -- \
|
||||
--actor "notary" \
|
||||
--actor "attester" \
|
||||
--deposit \
|
||||
--datadir /path/to/your/datadir \
|
||||
--password /path/to/your/password.txt \
|
||||
--networkid 12345
|
||||
```
|
||||
|
||||
This will extract 1000ETH from your account balance and insert you into the SMC's notaries. Then, the program will listen for incoming block headers and notify you when you have been selected as to vote on proposals for a certain shard in a given period. Once you are selected, your sharding node will download collation information to check for data availability on vote on proposals that have been submitted via the `addHeader` function on the SMC.
|
||||
This will extract 1000ETH from your account balance and insert you into the SMC's attesters. Then, the program will listen for incoming block headers and notify you when you have been selected as to vote on proposals for a certain shard in a given period. Once you are selected, your sharding node will download collation information to check for data availability on vote on proposals that have been submitted via the `addHeader` function on the SMC.
|
||||
|
||||
Concurrently, you will need to run another service that is tasked with processing transactions into collations and submitting them to the SMC via the `addHeader` function.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ This document serves as a main reference for Prysmatic Labs' sharding and beacon
|
||||
- [Beacon Chain and Sharding Alpha Implementation](#beacon-chain-and-sharding-alpha-implementation)
|
||||
- [System Architecture](#system-architecture)
|
||||
- [System Start and User Entrypoint](#system-start-and-user-entrypoint)
|
||||
- [Notary Sampling](#notary-sampling)
|
||||
- [Attester Sampling](#attester-sampling)
|
||||
- [Security Considerations](#security-considerations)
|
||||
- [Not Included in Ruby Release](#not-included-in-ruby-release)
|
||||
- [Enforced Windback](#enforced-windback)
|
||||
@@ -31,23 +31,23 @@ An approach to solving the scalability trilemma is the idea of blockchain shardi
|
||||
|
||||
## Basic Sharding Idea and Design
|
||||
|
||||
A sharded blockchain system is made possible by having nodes store “signed metadata” in the main chain of latest changes within each shard chain. Through this, we manage to create a layer of abstraction that tells us enough information about the global, synced state of parallel shard chains. These messages are called **cross-links**, which are specific structures that encompass important information about the shard blocks (known as **collations**) of a shard in question. Collations are created by actors known as **proposers** that are tasked with packaging transactions into collation bodies. These collations are then voted on by a party of actors known as **notaries**. These notaries are randomly selected for particular periods of time in certain shards and are then tasked into reaching consensus on these chains via a **proof of stake** system.
|
||||
A sharded blockchain system is made possible by having nodes store “signed metadata” in the main chain of latest changes within each shard chain. Through this, we manage to create a layer of abstraction that tells us enough information about the global, synced state of parallel shard chains. These messages are called **cross-links**, which are specific structures that encompass important information about the shard blocks (known as **collations**) of a shard in question. Collations are created by actors known as **proposers** that are tasked with packaging transactions into collation bodies. These collations are then voted on by a party of actors known as **attesters**. These attesters are randomly selected for particular periods of time in certain shards and are then tasked into reaching consensus on these chains via a **proof of stake** system.
|
||||
|
||||
Cross-links are stored in blocks on a full proof of stake chain known as a **beacon chain**, which will be implemented as a sidechain to the Ethereum main chain initially.
|
||||
|
||||
Cross-links are holistic descriptions of the state and transactions on a certain shard. Transactions in a shard are stored in **collations** which contain both a collation header and collation body A collation header at its most basic, high level summary contains information about who created it, when it was added to a shard, and its internal data stored as serialized blobs.
|
||||
|
||||
For detailed information on protocol primitives including collations, see: [Protocol Primitives](#protocol-primitives). We will have a few types of nodes that do the heavy lifting of our sharding logic: **proposers, notaries, and attesters**. The basic role of proposers is to fetch pending transactions from the txpool, wrap them into collations, grow the shard chains, and submit cross-links to the beacon chain.
|
||||
For detailed information on protocol primitives including collations, see: [Protocol Primitives](#protocol-primitives). We will have a few types of nodes that do the heavy lifting of our sharding logic: **proposers, attesters, and attesters**. The basic role of proposers is to fetch pending transactions from the txpool, wrap them into collations, grow the shard chains, and submit cross-links to the beacon chain.
|
||||
|
||||
We still keep the Ethereum main chain and deploy a smart contract into it known as the **Validator Registration Contract**, where users can deposit and burn 32 ETH. Beacon chain nodes would listen to deposits in this contract and consequently queue up a user with the associated address as a validator in the beacon chain PoS system. Validators then become part of a registered validator set in the beacon chain, and are committees of validators are selected to become notaries on shard chains in certain periods of blocks until they are ventually reshuffled into different shards.
|
||||
We still keep the Ethereum main chain and deploy a smart contract into it known as the **Validator Registration Contract**, where users can deposit and burn 32 ETH. Beacon chain nodes would listen to deposits in this contract and consequently queue up a user with the associated address as a validator in the beacon chain PoS system. Validators then become part of a registered validator set in the beacon chain, and are committees of validators are selected to become attesters on shard chains in certain periods of blocks until they are ventually reshuffled into different shards.
|
||||
|
||||
Notaries are in charge of checking for data availability of such collations and reach consensus on canonical shard chains. So then, are proposers in charge of state execution? The short answer is that phase 1 will contain **no state execution**. Instead, proposers will simply package all types of transactions into collations and later down the line, agents known as executors will download, run, and validate state as they need to through possibly different types of execution engines (potentially TrueBit-style, interactive execution).
|
||||
Attesters are in charge of checking for data availability of such collations and reach consensus on canonical shard chains. So then, are proposers in charge of state execution? The short answer is that phase 1 will contain **no state execution**. Instead, proposers will simply package all types of transactions into collations and later down the line, agents known as executors will download, run, and validate state as they need to through possibly different types of execution engines (potentially TrueBit-style, interactive execution).
|
||||
|
||||
This separation of concerns between notaries and proposers allows for more computational efficiency within the system, as notaries will not have to do the heavy lifting of state execution and focus solely on consensus through fork-choice rules. In this scheme, it makes sense that eventually **proposers** will become **executors** in later phases of a sharding spec.
|
||||
This separation of concerns between attesters and proposers allows for more computational efficiency within the system, as attesters will not have to do the heavy lifting of state execution and focus solely on consensus through fork-choice rules. In this scheme, it makes sense that eventually **proposers** will become **executors** in later phases of a sharding spec.
|
||||
|
||||
Given that we are splitting up the global state of the Ethereum blockchain into shards, new types of attacks arise because fewer resources are required to completely dominate a shard. This is why a **source of randomness** and periods are critical components to ensuring the integrity of the system.
|
||||
|
||||
The Ethereum Wiki’s [Sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQ) suggests pseudorandom sampling of notaries on each shard. The goal is so that these notaries will not know which shard they will get in advance. Otherwise, malicious actors could concentrate resources into a single shard and try to overtake it (See: [1% Attack](https://medium.com/@icebearhww/ethereum-sharding-and-finality-65248951f649)).
|
||||
The Ethereum Wiki’s [Sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQ) suggests pseudorandom sampling of attesters on each shard. The goal is so that these attesters will not know which shard they will get in advance. Otherwise, malicious actors could concentrate resources into a single shard and try to overtake it (See: [1% Attack](https://medium.com/@icebearhww/ethereum-sharding-and-finality-65248951f649)).
|
||||
|
||||
Sharding revolves around being able to store shard metadata in a full proof of stake chain known as a beacon chain. For pseudorandomness generation, a RANDAO mechanism can be used in the beacon chain to shuffle validators securely.
|
||||
|
||||
@@ -64,7 +64,7 @@ Our current work is focused on creating a localized version of a beacon chain wi
|
||||
- A minimal, **beacon chain node** that will interact with a main chain geth node via JSON-RPC
|
||||
- A **Validator Registration Contract** deployed on the main chain where a beacon node can read logs to check for registered validators
|
||||
- A minimal, gossipsub shardp2p network
|
||||
- Ability for proposers/notaries/attesters to be selected by the beacon chain's randomness into committees that work on specific shards
|
||||
- Ability for proposers/attesters/attesters to be selected by the beacon chain's randomness into committees that work on specific shards
|
||||
- Ability to serialize blobs into collations on shard chains and advance the growth of the shard chains
|
||||
- An observer node that can join a network on shardp2p, sync to the latest head, and send tx's to nodes in the network
|
||||
|
||||
@@ -75,7 +75,7 @@ ETA: To be determined
|
||||
|
||||
## The Sapphire Release: Ropsten Testnet
|
||||
|
||||
Part 1 of the **Sapphire Release** will focus around getting the **Ruby Release** polished enough to be live on an Ethereum testnet and manage a a beacon chain + sharding system. This will require a lot more elaborate simulations around the safety of the randomness behind the notary assignments in the SMC. Futhermore we need to pass stress testing against DoS and other sorts of byzantine attacks. Additionally, it will be the first release to have real users proposing collations concurrently with notaries reaching consensus on these collations, alongside beacon node validators producing blocks via PoS.
|
||||
Part 1 of the **Sapphire Release** will focus around getting the **Ruby Release** polished enough to be live on an Ethereum testnet and manage a a beacon chain + sharding system. This will require a lot more elaborate simulations around the safety of the randomness behind the attester assignments in the SMC. Futhermore we need to pass stress testing against DoS and other sorts of byzantine attacks. Additionally, it will be the first release to have real users proposing collations concurrently with attesters reaching consensus on these collations, alongside beacon node validators producing blocks via PoS.
|
||||
|
||||
Part 2 of the **Sapphire Release** will focus on implementing state execution and defining the State Transition Function for sharding on a local testnet (as outlined in [Beyond Phase 1](#beyond-phase-1)) as an extenstion to the Ruby Release.
|
||||
|
||||
@@ -91,7 +91,7 @@ ETA: To Be determined
|
||||
|
||||
# Beacon Chain and Sharding Alpha Implementation
|
||||
|
||||
Prysmatic Labs will begin by focusing its implementation entirely on the **Ruby Release** from our roadmap. We plan on being as pragmatic as possible to create something that can be locally run by any developer as soon as possible. Our initial deliverable will center around a command line tool that will serve as an entrypoint into a beacon chain node that allows for users to become a notary, proposer, and to manage the growth of shard chains.
|
||||
Prysmatic Labs will begin by focusing its implementation entirely on the **Ruby Release** from our roadmap. We plan on being as pragmatic as possible to create something that can be locally run by any developer as soon as possible. Our initial deliverable will center around a command line tool that will serve as an entrypoint into a beacon chain node that allows for users to become a attester, proposer, and to manage the growth of shard chains.
|
||||
|
||||
Here is a reference spec explaining how our initial system will function:
|
||||
|
||||
@@ -109,7 +109,7 @@ A basic, end-to-end example of the system is as follows:
|
||||
|
||||
2. _**Registered validator begins PoS process to propose blocks:**_ the PoS validator has the resposibility to participate in the addition of new blocks to the beacon chain
|
||||
|
||||
3. _**RANDAO mechanism selects committees of proposers/notaries/attesters for shards:**_ the beacon chain node will use its RANDAO mechanism to select committees of proposers, notaries, and attesters that each have responsibilities within the sharding system. Refer to the [Full Casper Chain V2 Doc](https://ethresear.ch/t/convenience-link-to-full-casper-chain-v2-spec/2332) for extensive detail on the different fields in the state of the beacon chain related to sharding
|
||||
3. _**RANDAO mechanism selects committees of proposers/attesters/attesters for shards:**_ the beacon chain node will use its RANDAO mechanism to select committees of proposers, attesters, and attesters that each have responsibilities within the sharding system. Refer to the [Full Casper Chain V2 Doc](https://ethresear.ch/t/convenience-link-to-full-casper-chain-v2-spec/2332) for extensive detail on the different fields in the state of the beacon chain related to sharding
|
||||
|
||||
4. _**Beacon Chain State Advances, Committees are Reshuffled:**_ upon completing responsibilities, the different actors of the sharding system are them reshuffled into new committees on different shards
|
||||
|
||||
@@ -119,21 +119,21 @@ Our Ruby Release requires users to start a local geth node running a localized,
|
||||
|
||||
1. _**Sync to the latest block header on the beacon chain:**_ the node will begin a sync process for the beacon chain
|
||||
|
||||
2. _**Assign the validator as a proposer/notary/attester based on RANDAO mechanism:**_ on incoming headers, the client will interact with the SMC to check if the current user is an eligible notary for an upcoming period (only a few minutes notice)
|
||||
2. _**Assign the validator as a proposer/attester/attester based on RANDAO mechanism:**_ on incoming headers, the client will interact with the SMC to check if the current user is an eligible attester for an upcoming period (only a few minutes notice)
|
||||
|
||||
3. _**Process shard cross-links:**_ once a notary is selected, he/she has to download subimtted collation headers for the shard in a certain period and check for their data availability
|
||||
3. _**Process shard cross-links:**_ once a attester is selected, he/she has to download subimtted collation headers for the shard in a certain period and check for their data availability
|
||||
|
||||
5. _**Reshuffle committees**_ the notary votes on the available collation header that came first in the submissions.
|
||||
5. _**Reshuffle committees**_ the attester votes on the available collation header that came first in the submissions.
|
||||
|
||||
6. _**Propose blocks and finalize incoming blocks via PoS:**_ Once notaries vote, headers that received >=2/3 votes are selected as canonical
|
||||
6. _**Propose blocks and finalize incoming blocks via PoS:**_ Once attesters vote, headers that received >=2/3 votes are selected as canonical
|
||||
|
||||
## Notary Sampling
|
||||
## Attester Sampling
|
||||
|
||||
The probability of being selected as a notary on a particular shard is being heavily researched in the latest ETHResearch discussions. As specified in the [Sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQ) by Vitalik, “if validators [collators] could choose, then attackers with small total stake could concentrate their stake onto one shard and attack it, thereby eliminating the system’s security.”
|
||||
The probability of being selected as a attester on a particular shard is being heavily researched in the latest ETHResearch discussions. As specified in the [Sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQ) by Vitalik, “if validators [collators] could choose, then attackers with small total stake could concentrate their stake onto one shard and attack it, thereby eliminating the system’s security.”
|
||||
|
||||
The idea is that notaries should not be able to figure out which shard they will become a notary of and during which period they will be assigned with anything more than a few minutes notice.
|
||||
The idea is that attesters should not be able to figure out which shard they will become a attester of and during which period they will be assigned with anything more than a few minutes notice.
|
||||
|
||||
Ideally, we want notaries to shuffle across shards very rapidly and through a source of pseudorandomness built in-protocol.
|
||||
Ideally, we want attesters to shuffle across shards very rapidly and through a source of pseudorandomness built in-protocol.
|
||||
|
||||
Despite its benefits, random sampling does not help in a bribing, coordinated attack model. In Vitalik’s own words:
|
||||
|
||||
@@ -176,13 +176,13 @@ Additionally, we will be using simple blockhashes for randomness in committee se
|
||||
|
||||
## Enforced Windback
|
||||
|
||||
When notaries are extending shard chains, it is critical that they are able to verify some of the collation headers in the immediate past for security purposes. There have already been instances where mining blindly has led to invalid transactions that forced Bitcoin to undergo a fork (See: [BIP66 Incident](https://bitcoin.stackexchange.com/questions/38437/what-is-spv-mining-and-how-did-it-inadvertently-cause-the-fork-after-bip66-wa)).
|
||||
When attesters are extending shard chains, it is critical that they are able to verify some of the collation headers in the immediate past for security purposes. There have already been instances where mining blindly has led to invalid transactions that forced Bitcoin to undergo a fork (See: [BIP66 Incident](https://bitcoin.stackexchange.com/questions/38437/what-is-spv-mining-and-how-did-it-inadvertently-cause-the-fork-after-bip66-wa)).
|
||||
|
||||
This process of checking previous blocks is known as **“windback”**. In a [post](https://ethresear.ch/t/enforcing-windback-validity-and-availability-and-a-proof-of-custody/949) by Justin Drake on ETHResearch, he outlines that this is necessary for security, but is counterintuitive to the end-goal of scalability as this obviously imposes more computational and network constraints on nodes.
|
||||
|
||||
One way to enforce **validity** during the windback process is for nodes to produce zero-knowedge proofs of validity that can then be stored in collation headers for quick verification.
|
||||
|
||||
On the other hand, to enforce **availability** for the windback process, a possible approach is for nodes to produce “proofs of custody” in collation headers that prove the notary was in possession of the full data of a collation when produced. Drake proposes a constant time, non-interactive zkSNARK method for notaries to check these proofs of custody. In his construction, he mentions splitting up a collation body into “chunks” that are then mixed with the node's private key through a hashing scheme. The security in this relies in the idea that a node would not leak his/her private key without compromising him or herself, so it provides a succinct way of checking if the full data was available when a node processed the collation body and proof was created.
|
||||
On the other hand, to enforce **availability** for the windback process, a possible approach is for nodes to produce “proofs of custody” in collation headers that prove the attester was in possession of the full data of a collation when produced. Drake proposes a constant time, non-interactive zkSNARK method for attesters to check these proofs of custody. In his construction, he mentions splitting up a collation body into “chunks” that are then mixed with the node's private key through a hashing scheme. The security in this relies in the idea that a node would not leak his/her private key without compromising him or herself, so it provides a succinct way of checking if the full data was available when a node processed the collation body and proof was created.
|
||||
|
||||
# Active Questions and Research
|
||||
|
||||
@@ -231,7 +231,7 @@ A special thanks for entire [Prysmatic Labs](https://gitter.im/prysmaticlabs/pry
|
||||
|
||||
[Data Availability Proof-friendly State Tree Transitions](https://ethresear.ch/t/data-availability-proof-friendly-state-tree-transitions/1453)
|
||||
|
||||
[Safety Notary Pool Size](https://ethresear.ch/t/safe-notary-pool-size/1728)
|
||||
[Safety Attester Pool Size](https://ethresear.ch/t/safe-attester-pool-size/1728)
|
||||
|
||||
[Fixed Size Deposits and Rewards Penalties Quadleak](https://ethresear.ch/t/fixed-size-deposits-and-rewards-penalties-quad-leak/2073/7)
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"notary.go",
|
||||
"attester.go",
|
||||
"service.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/client/notary",
|
||||
importpath = "github.com/prysmaticlabs/prysm/client/attester",
|
||||
visibility = ["//client:__subpackages__"],
|
||||
deps = [
|
||||
"//client/contracts:go_default_library",
|
||||
@@ -1,4 +1,4 @@
|
||||
package notary
|
||||
package attester
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
// subscribeBlockHeaders checks incoming block headers and determines if
|
||||
// we are an eligible notary for collations. Then, it finds the pending tx's
|
||||
// we are an eligible attester for collations. Then, it finds the pending tx's
|
||||
// from the running geth node and sorts them by descending order of gas price,
|
||||
// eliminates those that ask for too much gas, and routes them over
|
||||
// to the SMC to create a collation.
|
||||
@@ -34,45 +34,45 @@ func subscribeBlockHeaders(reader mainchain.Reader, caller mainchain.ContractCal
|
||||
for {
|
||||
// TODO: Error handling for getting disconnected from the client.
|
||||
head := <-headerChan
|
||||
// Query the current state to see if we are an eligible notary.
|
||||
// Query the current state to see if we are an eligible attester.
|
||||
log.WithFields(logrus.Fields{
|
||||
"number": head.Number.String(),
|
||||
}).Info("Received new header")
|
||||
|
||||
// Check if we are in the notary pool before checking if we are an eligible notary.
|
||||
v, err := isAccountInNotaryPool(caller, account)
|
||||
// Check if we are in the attester pool before checking if we are an eligible attester.
|
||||
v, err := isAccountInAttesterPool(caller, account)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to verify client in notary pool. %v", err)
|
||||
return fmt.Errorf("unable to verify client in attester pool. %v", err)
|
||||
}
|
||||
|
||||
if v {
|
||||
if err := checkSMCForNotary(caller, account); err != nil {
|
||||
if err := checkSMCForAttester(caller, account); err != nil {
|
||||
return fmt.Errorf("unable to watch shards. %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkSMCForNotary checks if we are an eligible notary for
|
||||
// checkSMCForAttester checks if we are an eligible attester for
|
||||
// collation for the available shards in the SMC. The function calls
|
||||
// getEligibleNotary from the SMC and notary a collation if
|
||||
// getEligibleAttester from the SMC and attester a collation if
|
||||
// conditions are met.
|
||||
func checkSMCForNotary(caller mainchain.ContractCaller, account *accounts.Account) error {
|
||||
log.Info("Checking if we are an eligible collation notary for a shard...")
|
||||
func checkSMCForAttester(caller mainchain.ContractCaller, account *accounts.Account) error {
|
||||
log.Info("Checking if we are an eligible collation attester for a shard...")
|
||||
shardCount, err := caller.GetShardCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get shard count from smc: %v", err)
|
||||
}
|
||||
for s := int64(0); s < shardCount; s++ {
|
||||
// Checks if we are an eligible notary according to the SMC.
|
||||
addr, err := caller.SMCCaller().GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(s))
|
||||
// Checks if we are an eligible attester according to the SMC.
|
||||
addr, err := caller.SMCCaller().GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(s))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if addr == account.Address {
|
||||
log.Infof("Selected as notary on shard: %d", s)
|
||||
log.Infof("Selected as attester on shard: %d", s)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,61 +80,61 @@ func checkSMCForNotary(caller mainchain.ContractCaller, account *accounts.Accoun
|
||||
return nil
|
||||
}
|
||||
|
||||
// getNotaryRegistry retrieves the registry of the registered account.
|
||||
func getNotaryRegistry(caller mainchain.ContractCaller, account *accounts.Account) (*contracts.Registry, error) {
|
||||
// getAttesterRegistry retrieves the registry of the registered account.
|
||||
func getAttesterRegistry(caller mainchain.ContractCaller, account *accounts.Account) (*contracts.Registry, error) {
|
||||
|
||||
var nreg contracts.Registry
|
||||
nreg, err := caller.SMCCaller().NotaryRegistry(&bind.CallOpts{}, account.Address)
|
||||
nreg, err := caller.SMCCaller().AttesterRegistry(&bind.CallOpts{}, account.Address)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to retrieve notary registry: %v", err)
|
||||
return nil, fmt.Errorf("unable to retrieve attester registry: %v", err)
|
||||
}
|
||||
|
||||
return &nreg, nil
|
||||
}
|
||||
|
||||
// isAccountInNotaryPool checks if the user is in the notary pool because
|
||||
// isAccountInAttesterPool checks if the user is in the attester pool because
|
||||
// we can't guarantee our tx for deposit will be in the next block header we receive.
|
||||
// The function calls IsNotaryDeposited from the SMC and returns true if
|
||||
// the user is in the notary pool.
|
||||
func isAccountInNotaryPool(caller mainchain.ContractCaller, account *accounts.Account) (bool, error) {
|
||||
// The function calls IsAttesterDeposited from the SMC and returns true if
|
||||
// the user is in the attester pool.
|
||||
func isAccountInAttesterPool(caller mainchain.ContractCaller, account *accounts.Account) (bool, error) {
|
||||
|
||||
nreg, err := getNotaryRegistry(caller, account)
|
||||
nreg, err := getAttesterRegistry(caller, account)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !nreg.Deposited {
|
||||
log.Warnf("Account %s not in notary pool.", account.Address.Hex())
|
||||
log.Warnf("Account %s not in attester pool.", account.Address.Hex())
|
||||
}
|
||||
|
||||
return nreg.Deposited, nil
|
||||
}
|
||||
|
||||
// joinNotaryPool checks if the deposit flag is true and the account is a
|
||||
// notary in the SMC. If the account is not in the set, it will deposit ETH
|
||||
// joinAttesterPool checks if the deposit flag is true and the account is a
|
||||
// attester in the SMC. If the account is not in the set, it will deposit ETH
|
||||
// into contract.
|
||||
func joinNotaryPool(manager mainchain.ContractManager, client mainchain.EthClient) error {
|
||||
func joinAttesterPool(manager mainchain.ContractManager, client mainchain.EthClient) error {
|
||||
if !client.DepositFlag() {
|
||||
return errors.New("joinNotaryPool called when deposit flag was not set")
|
||||
return errors.New("joinAttesterPool called when deposit flag was not set")
|
||||
}
|
||||
|
||||
if b, err := isAccountInNotaryPool(manager, client.Account()); b || err != nil {
|
||||
if b, err := isAccountInAttesterPool(manager, client.Account()); b || err != nil {
|
||||
if b {
|
||||
log.Info("Already joined notary pool")
|
||||
log.Info("Already joined attester pool")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Joining notary pool")
|
||||
txOps, err := manager.CreateTXOpts(shardparams.DefaultConfig.NotaryDeposit)
|
||||
log.Info("Joining attester pool")
|
||||
txOps, err := manager.CreateTXOpts(shardparams.DefaultConfig.AttesterDeposit)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initiate the deposit transaction: %v", err)
|
||||
}
|
||||
|
||||
tx, err := manager.SMCTransactor().RegisterNotary(txOps)
|
||||
tx, err := manager.SMCTransactor().RegisterAttester(txOps)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to deposit eth and become a notary: %v", err)
|
||||
return fmt.Errorf("unable to deposit eth and become a attester: %v", err)
|
||||
}
|
||||
|
||||
err = client.WaitForTransaction(context.Background(), tx.Hash(), 400)
|
||||
@@ -147,17 +147,17 @@ func joinNotaryPool(manager mainchain.ContractManager, client mainchain.EthClien
|
||||
return err
|
||||
}
|
||||
if receipt.Status == gethTypes.ReceiptStatusFailed {
|
||||
return errors.New("transaction was not successful, unable to deposit ETH and become a notary")
|
||||
return errors.New("transaction was not successful, unable to deposit ETH and become a attester")
|
||||
}
|
||||
|
||||
if inPool, err := isAccountInNotaryPool(manager, client.Account()); !inPool || err != nil {
|
||||
if inPool, err := isAccountInAttesterPool(manager, client.Account()); !inPool || err != nil {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New("account has not been able to be deposited in notary pool")
|
||||
return errors.New("account has not been able to be deposited in attester pool")
|
||||
}
|
||||
|
||||
log.Infof("Deposited %dETH into contract with transaction hash: %s", new(big.Int).Div(shardparams.DefaultConfig.NotaryDeposit, big.NewInt(params.Ether)), tx.Hash().Hex())
|
||||
log.Infof("Deposited %dETH into contract with transaction hash: %s", new(big.Int).Div(shardparams.DefaultConfig.AttesterDeposit, big.NewInt(params.Ether)), tx.Hash().Hex())
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package notary defines all relevant functionality for a Notary actor
|
||||
// Package attester defines all relevant functionality for a Attester actor
|
||||
// within a sharded Ethereum blockchain.
|
||||
package notary
|
||||
package attester
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/client/database"
|
||||
@@ -10,43 +10,43 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "notary")
|
||||
var log = logrus.WithField("prefix", "attester")
|
||||
|
||||
// Notary holds functionality required to run a collation notary
|
||||
// Attester holds functionality required to run a collation attester
|
||||
// in a sharded system. Must satisfy the Service interface defined in
|
||||
// sharding/service.go.
|
||||
type Notary struct {
|
||||
type Attester struct {
|
||||
config *params.Config
|
||||
smcClient *mainchain.SMCClient
|
||||
p2p *p2p.Server
|
||||
dbService *database.ShardDB
|
||||
}
|
||||
|
||||
// NewNotary creates a new notary instance.
|
||||
func NewNotary(config *params.Config, smcClient *mainchain.SMCClient, p2p *p2p.Server, dbService *database.ShardDB) (*Notary, error) {
|
||||
return &Notary{config, smcClient, p2p, dbService}, nil
|
||||
// NewAttester creates a new attester instance.
|
||||
func NewAttester(config *params.Config, smcClient *mainchain.SMCClient, p2p *p2p.Server, dbService *database.ShardDB) (*Attester, error) {
|
||||
return &Attester{config, smcClient, p2p, dbService}, nil
|
||||
}
|
||||
|
||||
// Start the main routine for a notary.
|
||||
func (n *Notary) Start() {
|
||||
log.Info("Starting notary service")
|
||||
// Start the main routine for a attester.
|
||||
func (n *Attester) Start() {
|
||||
log.Info("Starting attester service")
|
||||
go n.notarizeCollations()
|
||||
}
|
||||
|
||||
// Stop the main loop for notarizing collations.
|
||||
func (n *Notary) Stop() error {
|
||||
log.Info("Stopping notary service")
|
||||
func (n *Attester) Stop() error {
|
||||
log.Info("Stopping attester service")
|
||||
return nil
|
||||
}
|
||||
|
||||
// notarizeCollations checks incoming block headers and determines if
|
||||
// we are an eligible notary for collations.
|
||||
func (n *Notary) notarizeCollations() {
|
||||
// we are an eligible attester for collations.
|
||||
func (n *Attester) notarizeCollations() {
|
||||
|
||||
// TODO: handle this better through goroutines. Right now, these methods
|
||||
// are blocking.
|
||||
if n.smcClient.DepositFlag() {
|
||||
if err := joinNotaryPool(n.smcClient, n.smcClient); err != nil {
|
||||
if err := joinAttesterPool(n.smcClient, n.smcClient); err != nil {
|
||||
log.Errorf("Could not fetch current block number: %v", err)
|
||||
return
|
||||
}
|
||||
101
client/attester/service_test.go
Normal file
101
client/attester/service_test.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package attester
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/prysmaticlabs/prysm/client/internal"
|
||||
shardparams "github.com/prysmaticlabs/prysm/client/params"
|
||||
"github.com/prysmaticlabs/prysm/client/types"
|
||||
)
|
||||
|
||||
// Verifies that Attester implements the Actor interface.
|
||||
var _ = types.Actor(&Attester{})
|
||||
|
||||
func TestHasAccountBeenDeregistered(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend, BlockNumber: 1}
|
||||
|
||||
client.SetDepositFlag(true)
|
||||
err := joinAttesterPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAccountInAttesterPool(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend}
|
||||
|
||||
// address should not be in pool initially.
|
||||
b, err := isAccountInAttesterPool(client, client.Account())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b {
|
||||
t.Fatal("account unexpectedly in attester pool")
|
||||
}
|
||||
|
||||
txOpts, _ := client.CreateTXOpts(shardparams.DefaultConfig.AttesterDeposit)
|
||||
if _, err := smc.RegisterAttester(txOpts); err != nil {
|
||||
t.Fatalf("Failed to deposit: %v", err)
|
||||
}
|
||||
client.CommitWithBlock()
|
||||
b, err = isAccountInAttesterPool(client, client.Account())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !b {
|
||||
t.Error("account not in attester pool when expected to be")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinAttesterPool(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend}
|
||||
|
||||
// There should be no attester initially.
|
||||
numAttesters, err := smc.AttesterPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(0).Cmp(numAttesters) != 0 {
|
||||
t.Errorf("unexpected number of attesters. Got %d, wanted 0.", numAttesters)
|
||||
}
|
||||
|
||||
client.SetDepositFlag(false)
|
||||
err = joinAttesterPool(client, client)
|
||||
if err == nil {
|
||||
t.Error("joined attester pool while --deposit was not present")
|
||||
}
|
||||
|
||||
client.SetDepositFlag(true)
|
||||
err = joinAttesterPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Now there should be one attester.
|
||||
numAttesters, err = smc.AttesterPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(1).Cmp(numAttesters) != 0 {
|
||||
t.Errorf("unexpected number of attesters. Got %d, wanted 1", numAttesters)
|
||||
}
|
||||
|
||||
// Join while deposited should do nothing.
|
||||
err = joinAttesterPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
numAttesters, err = smc.AttesterPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(1).Cmp(numAttesters) != 0 {
|
||||
t.Errorf("unexpected number of attesters. Got %d, wanted 1", numAttesters)
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -3,12 +3,12 @@ pragma solidity ^0.4.23;
|
||||
|
||||
contract SMC {
|
||||
event HeaderAdded(uint indexed shardId, bytes32 chunkRoot, uint period, address proposerAddress);
|
||||
event NotaryRegistered(address notary, uint poolIndex);
|
||||
event NotaryDeregistered(address notary, uint poolIndex, uint deregisteredPeriod);
|
||||
event NotaryReleased(address notary, uint poolIndex);
|
||||
event VoteSubmitted(uint indexed shardId, bytes32 chunkRoot, uint period, address notaryAddress);
|
||||
event AttesterRegistered(address attester, uint poolIndex);
|
||||
event AttesterDeregistered(address attester, uint poolIndex, uint deregisteredPeriod);
|
||||
event AttesterReleased(address attester, uint poolIndex);
|
||||
event VoteSubmitted(uint indexed shardId, bytes32 chunkRoot, uint period, address attesterAddress);
|
||||
|
||||
struct Notary {
|
||||
struct Attester {
|
||||
uint deregisteredPeriod;
|
||||
uint poolIndex;
|
||||
uint balance;
|
||||
@@ -22,14 +22,14 @@ contract SMC {
|
||||
bytes32 signature; // Signature of the collation header after proposer signs
|
||||
}
|
||||
|
||||
// Notary state variables
|
||||
address[] public notaryPool;
|
||||
// notaryAddress => notaryStruct
|
||||
mapping (address => Notary) public notaryRegistry;
|
||||
// number of notaries
|
||||
uint public notaryPoolLength;
|
||||
// Attester state variables
|
||||
address[] public attesterPool;
|
||||
// attesterAddress => attesterStruct
|
||||
mapping (address => Attester) public attesterRegistry;
|
||||
// number of attesters
|
||||
uint public attesterPoolLength;
|
||||
// current vote count of each shard
|
||||
// first 31 bytes are bitfield of notary's vote
|
||||
// first 31 bytes are bitfield of attester's vote
|
||||
// last 1 byte is the number of the total votes
|
||||
mapping (uint => bytes32) public currentVote;
|
||||
|
||||
@@ -42,13 +42,13 @@ contract SMC {
|
||||
mapping (uint => uint) public lastApprovedCollation;
|
||||
|
||||
// Internal help functions variables
|
||||
// Stack of empty notary slot indicies
|
||||
// Stack of empty attester slot indicies
|
||||
uint[] emptySlotsStack;
|
||||
// Top index of the stack
|
||||
uint emptySlotsStackTop;
|
||||
// Notary sample size at current period and next period
|
||||
uint currentPeriodNotarySampleSize;
|
||||
uint nextPeriodNotarySampleSize;
|
||||
// Attester sample size at current period and next period
|
||||
uint currentPeriodAttesterSampleSize;
|
||||
uint nextPeriodAttesterSampleSize;
|
||||
uint sampleSizeLastUpdatedPeriod;
|
||||
|
||||
// Number of shards
|
||||
@@ -56,115 +56,115 @@ contract SMC {
|
||||
uint public shardCount = 100;
|
||||
|
||||
// Constant values
|
||||
// Length of challenge period for notary's proof of custody
|
||||
// Length of challenge period for attester's proof of custody
|
||||
uint public constant CHALLENGE_PERIOD = 25;
|
||||
// Number of blocks per period
|
||||
uint constant PERIOD_LENGTH = 5;
|
||||
// The minimum deposit size for a notary
|
||||
uint constant NOTARY_DEPOSIT = 1000 ether;
|
||||
// Time the ether is locked by notaries
|
||||
uint constant NOTARY_LOCKUP_LENGTH = 16128;
|
||||
// Number of notaries to select from notary pool for each shard in each period
|
||||
// The minimum deposit size for a attester
|
||||
uint constant ATTESTER_DEPOSIT = 1000 ether;
|
||||
// Time the ether is locked by attesters
|
||||
uint constant ATTESTER_LOCKUP_LENGTH = 16128;
|
||||
// Number of attesters to select from attester pool for each shard in each period
|
||||
uint constant COMMITTEE_SIZE = 135;
|
||||
// Threshold(number of notaries in committee) for a proposal to be accepted
|
||||
// Threshold(number of attesters in committee) for a proposal to be accepted
|
||||
uint constant QUORUM_SIZE = 90;
|
||||
// Number of periods ahead of current period, which the contract
|
||||
// is able to return the notary of that period
|
||||
// is able to return the attester of that period
|
||||
uint constant LOOKAHEAD_LENGTH = 4;
|
||||
|
||||
/// Checks if a notary with given shard id and period has been chosen as
|
||||
/// Checks if a attester 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) public view returns(address) {
|
||||
function getAttesterInCommittee(uint _shardId) public view returns(address) {
|
||||
uint period = block.number / PERIOD_LENGTH;
|
||||
|
||||
updateNotarySampleSize();
|
||||
updateAttesterSampleSize();
|
||||
|
||||
// Determine notary pool length based on notary sample size
|
||||
// Determine attester pool length based on attester sample size
|
||||
uint sampleSize;
|
||||
if (period > sampleSizeLastUpdatedPeriod) {
|
||||
sampleSize = nextPeriodNotarySampleSize;
|
||||
sampleSize = nextPeriodAttesterSampleSize;
|
||||
} else {
|
||||
sampleSize = currentPeriodNotarySampleSize;
|
||||
sampleSize = currentPeriodAttesterSampleSize;
|
||||
}
|
||||
|
||||
// Get the notary pool index to concatenate with shardId and blockHash for random sample
|
||||
uint poolIndex = notaryRegistry[msg.sender].poolIndex;
|
||||
// Get the attester pool index to concatenate with shardId and blockHash for random sample
|
||||
uint poolIndex = attesterRegistry[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, poolIndex, _shardId)) % sampleSize;
|
||||
|
||||
return notaryPool[index];
|
||||
return attesterPool[index];
|
||||
}
|
||||
|
||||
/// Registers notary to notatery registry, locks in the notary deposit,
|
||||
/// Registers attester to notatery registry, locks in the attester deposit,
|
||||
/// and returns true on success
|
||||
function registerNotary() public payable {
|
||||
address notaryAddress = msg.sender;
|
||||
require(!notaryRegistry[notaryAddress].deposited);
|
||||
require(msg.value == NOTARY_DEPOSIT);
|
||||
function registerAttester() public payable {
|
||||
address attesterAddress = msg.sender;
|
||||
require(!attesterRegistry[attesterAddress].deposited);
|
||||
require(msg.value == ATTESTER_DEPOSIT);
|
||||
|
||||
updateNotarySampleSize();
|
||||
updateAttesterSampleSize();
|
||||
|
||||
uint index;
|
||||
if (emptyStack()) {
|
||||
index = notaryPoolLength;
|
||||
notaryPool.push(notaryAddress);
|
||||
index = attesterPoolLength;
|
||||
attesterPool.push(attesterAddress);
|
||||
} else {
|
||||
index = stackPop();
|
||||
notaryPool[index] = notaryAddress;
|
||||
attesterPool[index] = attesterAddress;
|
||||
}
|
||||
++notaryPoolLength;
|
||||
++attesterPoolLength;
|
||||
|
||||
notaryRegistry[notaryAddress] = Notary({
|
||||
attesterRegistry[attesterAddress] = Attester({
|
||||
deregisteredPeriod: 0,
|
||||
poolIndex: index,
|
||||
balance: msg.value,
|
||||
deposited: true
|
||||
});
|
||||
|
||||
// if current index is greater than notary sample size, increase notary sample size for next period
|
||||
if (index >= nextPeriodNotarySampleSize) {
|
||||
nextPeriodNotarySampleSize = index + 1;
|
||||
// if current index is greater than attester sample size, increase attester sample size for next period
|
||||
if (index >= nextPeriodAttesterSampleSize) {
|
||||
nextPeriodAttesterSampleSize = index + 1;
|
||||
}
|
||||
|
||||
emit NotaryRegistered(notaryAddress, index);
|
||||
emit AttesterRegistered(attesterAddress, index);
|
||||
}
|
||||
|
||||
/// Deregisters notary from notatery registry, lock up period countdowns down,
|
||||
/// notary may call releaseNotary after lock up period finishses to withdraw deposit,
|
||||
/// Deregisters attester from notatery registry, lock up period countdowns down,
|
||||
/// attester may call releaseAttester after lock up period finishses to withdraw deposit,
|
||||
/// and returns true on success
|
||||
function deregisterNotary() public {
|
||||
address notaryAddress = msg.sender;
|
||||
uint index = notaryRegistry[notaryAddress].poolIndex;
|
||||
require(notaryRegistry[notaryAddress].deposited);
|
||||
require(notaryPool[index] == notaryAddress);
|
||||
function deregisterAttester() public {
|
||||
address attesterAddress = msg.sender;
|
||||
uint index = attesterRegistry[attesterAddress].poolIndex;
|
||||
require(attesterRegistry[attesterAddress].deposited);
|
||||
require(attesterPool[index] == attesterAddress);
|
||||
|
||||
updateNotarySampleSize();
|
||||
updateAttesterSampleSize();
|
||||
|
||||
uint deregisteredPeriod = block.number / PERIOD_LENGTH;
|
||||
notaryRegistry[notaryAddress].deregisteredPeriod = deregisteredPeriod;
|
||||
attesterRegistry[attesterAddress].deregisteredPeriod = deregisteredPeriod;
|
||||
|
||||
stackPush(index);
|
||||
delete notaryPool[index];
|
||||
--notaryPoolLength;
|
||||
emit NotaryDeregistered(notaryAddress, index, deregisteredPeriod);
|
||||
delete attesterPool[index];
|
||||
--attesterPoolLength;
|
||||
emit AttesterDeregistered(attesterAddress, index, deregisteredPeriod);
|
||||
}
|
||||
|
||||
/// Removes an entry from notary registry, returns deposit back to the notary,
|
||||
/// Removes an entry from attester registry, returns deposit back to the attester,
|
||||
/// and returns true on success.
|
||||
function releaseNotary() public {
|
||||
address notaryAddress = msg.sender;
|
||||
uint index = notaryRegistry[notaryAddress].poolIndex;
|
||||
require(notaryRegistry[notaryAddress].deposited == true);
|
||||
require(notaryRegistry[notaryAddress].deregisteredPeriod != 0);
|
||||
require((block.number / PERIOD_LENGTH) > (notaryRegistry[notaryAddress].deregisteredPeriod + NOTARY_LOCKUP_LENGTH));
|
||||
function releaseAttester() public {
|
||||
address attesterAddress = msg.sender;
|
||||
uint index = attesterRegistry[attesterAddress].poolIndex;
|
||||
require(attesterRegistry[attesterAddress].deposited == true);
|
||||
require(attesterRegistry[attesterAddress].deregisteredPeriod != 0);
|
||||
require((block.number / PERIOD_LENGTH) > (attesterRegistry[attesterAddress].deregisteredPeriod + ATTESTER_LOCKUP_LENGTH));
|
||||
|
||||
uint balance = notaryRegistry[notaryAddress].balance;
|
||||
delete notaryRegistry[notaryAddress];
|
||||
notaryAddress.transfer(balance);
|
||||
emit NotaryReleased(notaryAddress, index);
|
||||
uint balance = attesterRegistry[attesterAddress].balance;
|
||||
delete attesterRegistry[attesterAddress];
|
||||
attesterAddress.transfer(balance);
|
||||
emit AttesterReleased(attesterAddress, index);
|
||||
}
|
||||
|
||||
/// Add collation header to the main chain, anyone can call this function. It emits a log
|
||||
@@ -178,7 +178,7 @@ contract SMC {
|
||||
require(_period == block.number / PERIOD_LENGTH);
|
||||
require(_period > lastSubmittedCollation[_shardId]);
|
||||
|
||||
updateNotarySampleSize();
|
||||
updateAttesterSampleSize();
|
||||
|
||||
collationRecords[_shardId][_period] = CollationRecord({
|
||||
chunkRoot: _chunkRoot,
|
||||
@@ -193,7 +193,7 @@ contract SMC {
|
||||
emit HeaderAdded(_shardId, _chunkRoot, _period, msg.sender);
|
||||
}
|
||||
|
||||
/// Sampled notary can call the following funtion to submit vote,
|
||||
/// Sampled attester can call the following funtion to submit vote,
|
||||
/// a vote log will be emitted for client to monitor
|
||||
function submitVote(
|
||||
uint _shardId,
|
||||
@@ -206,9 +206,9 @@ contract SMC {
|
||||
require(_period == lastSubmittedCollation[_shardId]);
|
||||
require(_index < COMMITTEE_SIZE);
|
||||
require(_chunkRoot == collationRecords[_shardId][_period].chunkRoot);
|
||||
require(notaryRegistry[msg.sender].deposited);
|
||||
require(attesterRegistry[msg.sender].deposited);
|
||||
require(!hasVoted(_shardId, _index));
|
||||
require(getNotaryInCommittee(_shardId) == msg.sender);
|
||||
require(getAttesterInCommittee(_shardId) == msg.sender);
|
||||
|
||||
castVote(_shardId, _index);
|
||||
uint voteCount = getVoteCount(_shardId);
|
||||
@@ -228,7 +228,7 @@ contract SMC {
|
||||
}
|
||||
|
||||
/// Check if a bit is set, this function is used to check
|
||||
/// if a notary has casted the vote. Right shift currentVote by index
|
||||
/// if a attester has casted the vote. Right shift currentVote by index
|
||||
/// and AND with 1, return true if voted, false if not
|
||||
function hasVoted(uint _shardId, uint _index) public view returns (bool) {
|
||||
uint votes = uint(currentVote[_shardId]);
|
||||
@@ -243,7 +243,7 @@ contract SMC {
|
||||
return emptySlotsStackTop == 0;
|
||||
}
|
||||
|
||||
/// Save one uint into the empty slots stack for notary to use later
|
||||
/// Save one uint into the empty slots stack for attester to use later
|
||||
function stackPush(uint _index) internal {
|
||||
if (emptySlotsStack.length == emptySlotsStackTop)
|
||||
emptySlotsStack.push(_index);
|
||||
@@ -253,31 +253,31 @@ contract SMC {
|
||||
++emptySlotsStackTop;
|
||||
}
|
||||
|
||||
/// To keep track of notary size in between periods, we call updateNotarySampleSize
|
||||
/// before notary registration/deregistration so correct size can be applied next period
|
||||
function updateNotarySampleSize() internal {
|
||||
/// To keep track of attester size in between periods, we call updateAttesterSampleSize
|
||||
/// before attester registration/deregistration so correct size can be applied next period
|
||||
function updateAttesterSampleSize() internal {
|
||||
uint currentPeriod = block.number / PERIOD_LENGTH;
|
||||
if (currentPeriod < sampleSizeLastUpdatedPeriod) {
|
||||
return;
|
||||
}
|
||||
currentPeriodNotarySampleSize = nextPeriodNotarySampleSize;
|
||||
currentPeriodAttesterSampleSize = nextPeriodAttesterSampleSize;
|
||||
sampleSizeLastUpdatedPeriod = currentPeriod;
|
||||
}
|
||||
|
||||
/// Get one uint out of the empty slots stack for notary index
|
||||
/// Get one uint out of the empty slots stack for attester index
|
||||
function stackPop() internal returns(uint) {
|
||||
require(emptySlotsStackTop > 1);
|
||||
--emptySlotsStackTop;
|
||||
return emptySlotsStack[emptySlotsStackTop];
|
||||
}
|
||||
|
||||
/// Set the index bit to one, notary uses this function to cast its vote,
|
||||
/// after the notary casts its vote, we increase currentVote's count by 1
|
||||
/// Set the index bit to one, attester uses this function to cast its vote,
|
||||
/// after the attester casts its vote, we increase currentVote's count by 1
|
||||
function castVote(uint _shardId, uint _index) internal {
|
||||
uint votes = uint(currentVote[_shardId]);
|
||||
// Get the bitfield by shifting 1 to the index
|
||||
uint indexToFlag = 2 ** (255 - _index);
|
||||
// OR with currentVote to cast notary index to 1
|
||||
// OR with currentVote to cast attester index to 1
|
||||
votes = votes | indexToFlag;
|
||||
// Update vote count
|
||||
votes++;
|
||||
|
||||
@@ -29,10 +29,10 @@ type testAccount struct {
|
||||
}
|
||||
|
||||
var (
|
||||
accountBalance2000Eth, _ = new(big.Int).SetString("2000000000000000000000", 10)
|
||||
notaryDepositInsufficient, _ = new(big.Int).SetString("999000000000000000000", 10)
|
||||
notaryDeposit, _ = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
ctx = context.Background()
|
||||
accountBalance2000Eth, _ = new(big.Int).SetString("2000000000000000000000", 10)
|
||||
attesterDepositInsufficient, _ = new(big.Int).SetString("999000000000000000000", 10)
|
||||
attesterDeposit, _ = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
// newSMCTestHelper is a helper function to initialize backend with the n test accounts,
|
||||
@@ -72,73 +72,73 @@ func (s *smcTestHelper) fastForward(p int) {
|
||||
}
|
||||
}
|
||||
|
||||
// registerNotaries is a helper function register notaries in batch.
|
||||
func (s *smcTestHelper) registerNotaries(deposit *big.Int, params ...int) error {
|
||||
// registerAttesters is a helper function register attesters in batch.
|
||||
func (s *smcTestHelper) registerAttesters(deposit *big.Int, params ...int) error {
|
||||
for i := params[0]; i < params[1]; i++ {
|
||||
s.testAccounts[i].txOpts.Value = deposit
|
||||
_, err := s.smc.RegisterNotary(s.testAccounts[i].txOpts)
|
||||
_, err := s.smc.RegisterAttester(s.testAccounts[i].txOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.backend.Commit()
|
||||
|
||||
notary, _ := s.smc.NotaryRegistry(&bind.CallOpts{}, s.testAccounts[i].addr)
|
||||
if !notary.Deposited ||
|
||||
notary.PoolIndex.Cmp(big.NewInt(int64(i))) != 0 ||
|
||||
notary.DeregisteredPeriod.Cmp(big.NewInt(0)) != 0 {
|
||||
return fmt.Errorf("Incorrect notary registry. Want - deposited:true, index:%v, period:0"+
|
||||
"Got - deposited:%v, index:%v, period:%v ", i, notary.Deposited, notary.PoolIndex, notary.DeregisteredPeriod)
|
||||
attester, _ := s.smc.AttesterRegistry(&bind.CallOpts{}, s.testAccounts[i].addr)
|
||||
if !attester.Deposited ||
|
||||
attester.PoolIndex.Cmp(big.NewInt(int64(i))) != 0 ||
|
||||
attester.DeregisteredPeriod.Cmp(big.NewInt(0)) != 0 {
|
||||
return fmt.Errorf("Incorrect attester registry. Want - deposited:true, index:%v, period:0"+
|
||||
"Got - deposited:%v, index:%v, period:%v ", i, attester.Deposited, attester.PoolIndex, attester.DeregisteredPeriod)
|
||||
}
|
||||
}
|
||||
// Filter SMC logs by notaryRegistered.
|
||||
log, err := s.smc.FilterNotaryRegistered(&bind.FilterOpts{})
|
||||
// Filter SMC logs by attesterRegistered.
|
||||
log, err := s.smc.FilterAttesterRegistered(&bind.FilterOpts{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Iterate notaryRegistered logs, compare each address and poolIndex.
|
||||
// Iterate attesterRegistered logs, compare each address and poolIndex.
|
||||
for i := 0; i < params[1]; i++ {
|
||||
log.Next()
|
||||
if log.Event.Notary != s.testAccounts[i].addr {
|
||||
return fmt.Errorf("incorrect address in notaryRegistered log. Want: %v Got: %v", s.testAccounts[i].addr, log.Event.Notary)
|
||||
if log.Event.Attester != s.testAccounts[i].addr {
|
||||
return fmt.Errorf("incorrect address in attesterRegistered log. Want: %v Got: %v", s.testAccounts[i].addr, log.Event.Attester)
|
||||
}
|
||||
// Verify notaryPoolIndex is incremental starting from 1st registered Notary.
|
||||
// Verify attesterPoolIndex is incremental starting from 1st registered Attester.
|
||||
if log.Event.PoolIndex.Cmp(big.NewInt(int64(i))) != 0 {
|
||||
return fmt.Errorf("incorrect index in notaryRegistered log. Want: %v Got: %v", i, log.Event.Notary)
|
||||
return fmt.Errorf("incorrect index in attesterRegistered log. Want: %v Got: %v", i, log.Event.Attester)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deregisterNotaries is a helper function that deregister notaries in batch.
|
||||
func (s *smcTestHelper) deregisterNotaries(params ...int) error {
|
||||
// deregisterAttesters is a helper function that deregister attesters in batch.
|
||||
func (s *smcTestHelper) deregisterAttesters(params ...int) error {
|
||||
for i := params[0]; i < params[1]; i++ {
|
||||
s.testAccounts[i].txOpts.Value = big.NewInt(0)
|
||||
_, err := s.smc.DeregisterNotary(s.testAccounts[i].txOpts)
|
||||
_, err := s.smc.DeregisterAttester(s.testAccounts[i].txOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to deregister notary: %v", err)
|
||||
return fmt.Errorf("Failed to deregister attester: %v", err)
|
||||
}
|
||||
s.backend.Commit()
|
||||
notary, _ := s.smc.NotaryRegistry(&bind.CallOpts{}, s.testAccounts[i].addr)
|
||||
if notary.DeregisteredPeriod.Cmp(big.NewInt(0)) == 0 {
|
||||
attester, _ := s.smc.AttesterRegistry(&bind.CallOpts{}, s.testAccounts[i].addr)
|
||||
if attester.DeregisteredPeriod.Cmp(big.NewInt(0)) == 0 {
|
||||
return fmt.Errorf("Degistered period can not be 0 right after deregistration")
|
||||
}
|
||||
}
|
||||
// Filter SMC logs by notaryDeregistered.
|
||||
log, err := s.smc.FilterNotaryDeregistered(&bind.FilterOpts{})
|
||||
// Filter SMC logs by attesterDeregistered.
|
||||
log, err := s.smc.FilterAttesterDeregistered(&bind.FilterOpts{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Iterate notaryDeregistered logs, compare each address, poolIndex and verify period is set.
|
||||
// Iterate attesterDeregistered logs, compare each address, poolIndex and verify period is set.
|
||||
for i := 0; i < params[1]; i++ {
|
||||
log.Next()
|
||||
if log.Event.Notary != s.testAccounts[i].addr {
|
||||
return fmt.Errorf("incorrect address in notaryDeregistered log. Want: %v Got: %v", s.testAccounts[i].addr, log.Event.Notary)
|
||||
if log.Event.Attester != s.testAccounts[i].addr {
|
||||
return fmt.Errorf("incorrect address in attesterDeregistered log. Want: %v Got: %v", s.testAccounts[i].addr, log.Event.Attester)
|
||||
}
|
||||
if log.Event.PoolIndex.Cmp(big.NewInt(int64(i))) != 0 {
|
||||
return fmt.Errorf("incorrect index in notaryDeregistered log. Want: %v Got: %v", i, log.Event.Notary)
|
||||
return fmt.Errorf("incorrect index in attesterDeregistered log. Want: %v Got: %v", i, log.Event.Attester)
|
||||
}
|
||||
if log.Event.DeregisteredPeriod.Cmp(big.NewInt(0)) == 0 {
|
||||
return fmt.Errorf("incorrect period in notaryDeregistered log. Got: %v", log.Event.DeregisteredPeriod)
|
||||
return fmt.Errorf("incorrect period in attesterDeregistered log. Got: %v", log.Event.DeregisteredPeriod)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -186,20 +186,20 @@ func (s *smcTestHelper) addHeader(a *testAccount, shard *big.Int, period *big.In
|
||||
return nil
|
||||
}
|
||||
|
||||
// submitVote is a helper function for notary to submit vote on a given header.
|
||||
// submitVote is a helper function for attester to submit vote on a given header.
|
||||
func (s *smcTestHelper) submitVote(a *testAccount, shard *big.Int, period *big.Int, index *big.Int, chunkRoot uint8) error {
|
||||
_, err := s.smc.SubmitVote(a.txOpts, shard, period, index, [32]byte{chunkRoot})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Notary submit vote failed: %v", err)
|
||||
return fmt.Errorf("Attester submit vote failed: %v", err)
|
||||
}
|
||||
s.backend.Commit()
|
||||
|
||||
v, err := s.smc.HasVoted(&bind.CallOpts{}, shard, index)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Check notary's vote failed: %v", err)
|
||||
return fmt.Errorf("Check attester's vote failed: %v", err)
|
||||
}
|
||||
if !v {
|
||||
return fmt.Errorf("Notary's indexd bit did not cast to 1 in index %v", index)
|
||||
return fmt.Errorf("Attester's indexd bit did not cast to 1 in index %v", index)
|
||||
}
|
||||
// Filter SMC logs by submitVote.
|
||||
shardIndex := []*big.Int{shard}
|
||||
@@ -209,8 +209,8 @@ func (s *smcTestHelper) submitVote(a *testAccount, shard *big.Int, period *big.I
|
||||
return err
|
||||
}
|
||||
log.Next()
|
||||
if log.Event.NotaryAddress != a.addr {
|
||||
return fmt.Errorf("incorrect notary address in submitVote log. Want: %v Got: %v", s.testAccounts[0].addr, a.addr)
|
||||
if log.Event.AttesterAddress != a.addr {
|
||||
return fmt.Errorf("incorrect attester address in submitVote log. Want: %v Got: %v", s.testAccounts[0].addr, a.addr)
|
||||
}
|
||||
if log.Event.ChunkRoot != [32]byte{chunkRoot} {
|
||||
return fmt.Errorf("chunk root missmatch in submitVote log. Want: %v Got: %v", common.BytesToHash([]byte{chunkRoot}), common.BytesToHash(log.Event.ChunkRoot[:]))
|
||||
@@ -218,15 +218,15 @@ func (s *smcTestHelper) submitVote(a *testAccount, shard *big.Int, period *big.I
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkNotaryPoolLength is a helper function to verify current notary pool
|
||||
// checkAttesterPoolLength is a helper function to verify current attester pool
|
||||
// length is equal to n.
|
||||
func checkNotaryPoolLength(smc *SMC, n *big.Int) error {
|
||||
numNotaries, err := smc.NotaryPoolLength(&bind.CallOpts{})
|
||||
func checkAttesterPoolLength(smc *SMC, n *big.Int) error {
|
||||
numAttesters, err := smc.AttesterPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get notary pool length: %v", err)
|
||||
return fmt.Errorf("Failed to get attester pool length: %v", err)
|
||||
}
|
||||
if numNotaries.Cmp(n) != 0 {
|
||||
return fmt.Errorf("Incorrect count from notary pool. Want: %v, Got: %v", n, numNotaries)
|
||||
if numAttesters.Cmp(n) != 0 {
|
||||
return fmt.Errorf("Incorrect count from attester pool. Want: %v, Got: %v", n, numAttesters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -239,311 +239,311 @@ func TestContractCreation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryRegister tests notary registers in a normal condition.
|
||||
func TestNotaryRegister(t *testing.T) {
|
||||
// Initializes 3 accounts to register as notaries.
|
||||
const notaryCount = 3
|
||||
s, _ := newSMCTestHelper(notaryCount)
|
||||
// TestAttesterRegister tests attester registers in a normal condition.
|
||||
func TestAttesterRegister(t *testing.T) {
|
||||
// Initializes 3 accounts to register as attesters.
|
||||
const attesterCount = 3
|
||||
s, _ := newSMCTestHelper(attesterCount)
|
||||
|
||||
// Verify notary 0 has not registered.
|
||||
notary, err := s.smc.NotaryRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
// Verify attester 0 has not registered.
|
||||
attester, err := s.smc.AttesterRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
if err != nil {
|
||||
t.Errorf("Can't get notary registry info: %v", err)
|
||||
t.Errorf("Can't get attester registry info: %v", err)
|
||||
}
|
||||
if notary.Deposited {
|
||||
t.Errorf("Notary has not registered. Got deposited flag: %v", notary.Deposited)
|
||||
if attester.Deposited {
|
||||
t.Errorf("Attester has not registered. Got deposited flag: %v", attester.Deposited)
|
||||
}
|
||||
|
||||
// Test notary 0 has registered.
|
||||
err = s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Test attester 0 has registered.
|
||||
err = s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Register notary failed: %v", err)
|
||||
t.Errorf("Register attester failed: %v", err)
|
||||
}
|
||||
// Test notary 1 and 2 have registered.
|
||||
err = s.registerNotaries(notaryDeposit, 1, 3)
|
||||
// Test attester 1 and 2 have registered.
|
||||
err = s.registerAttesters(attesterDeposit, 1, 3)
|
||||
if err != nil {
|
||||
t.Errorf("Register notary failed: %v", err)
|
||||
t.Errorf("Register attester failed: %v", err)
|
||||
}
|
||||
// Check total numbers of notaries in pool, should be 3
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(notaryCount))
|
||||
// Check total numbers of attesters in pool, should be 3
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(attesterCount))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryRegisterInsufficientEther tests notary registers with insufficient deposit.
|
||||
func TestNotaryRegisterInsufficientEther(t *testing.T) {
|
||||
// TestAttesterRegisterInsufficientEther tests attester registers with insufficient deposit.
|
||||
func TestAttesterRegisterInsufficientEther(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
if err := s.registerNotaries(notaryDepositInsufficient, 0, 1); err == nil {
|
||||
t.Errorf("Notary register should have failed with insufficient deposit")
|
||||
if err := s.registerAttesters(attesterDepositInsufficient, 0, 1); err == nil {
|
||||
t.Errorf("Attester register should have failed with insufficient deposit")
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryDoubleRegisters tests notary registers twice.
|
||||
func TestNotaryDoubleRegisters(t *testing.T) {
|
||||
// TestAttesterDoubleRegisters tests attester registers twice.
|
||||
func TestAttesterDoubleRegisters(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 registers.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Register notary failed: %v", err)
|
||||
t.Errorf("Register attester failed: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 registers again, This time should fail.
|
||||
if err = s.registerNotaries(big.NewInt(0), 0, 1); err == nil {
|
||||
t.Errorf("Notary register should have failed with double registers")
|
||||
// Attester 0 registers again, This time should fail.
|
||||
if err = s.registerAttesters(big.NewInt(0), 0, 1); err == nil {
|
||||
t.Errorf("Attester register should have failed with double registers")
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryDeregister tests notary deregisters in a normal condition.
|
||||
func TestNotaryDeregister(t *testing.T) {
|
||||
// TestAttesterDeregister tests attester deregisters in a normal condition.
|
||||
func TestAttesterDeregister(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 registers.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
// Fast forward 20 periods to check notary's deregistered period field is set correctly.
|
||||
// Fast forward 20 periods to check attester's deregistered period field is set correctly.
|
||||
s.fastForward(20)
|
||||
|
||||
// Notary 0 deregisters.
|
||||
s.deregisterNotaries(0, 1)
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(0))
|
||||
// Attester 0 deregisters.
|
||||
s.deregisterAttesters(0, 1)
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryDeregisterThenRegister tests notary deregisters then registers before lock up ends.
|
||||
func TestNotaryDeregisterThenRegister(t *testing.T) {
|
||||
// TestAttesterDeregisterThenRegister tests attester deregisters then registers before lock up ends.
|
||||
func TestAttesterDeregisterThenRegister(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 registers.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to register notary: %v", err)
|
||||
t.Errorf("Failed to register attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
|
||||
// Notary 0 deregisters.
|
||||
s.deregisterNotaries(0, 1)
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(0))
|
||||
// Attester 0 deregisters.
|
||||
s.deregisterAttesters(0, 1)
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 re-registers again.
|
||||
err = s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 re-registers again.
|
||||
err = s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err == nil {
|
||||
t.Error("Expected re-registration to fail")
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(0))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryRelease tests notary releases in a normal condition.
|
||||
func TestNotaryRelease(t *testing.T) {
|
||||
// TestAttesterRelease tests attester releases in a normal condition.
|
||||
func TestAttesterRelease(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 registers.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to register notary: %v", err)
|
||||
t.Errorf("Failed to register attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
|
||||
// Notary 0 deregisters.
|
||||
s.deregisterNotaries(0, 1)
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(0))
|
||||
// Attester 0 deregisters.
|
||||
s.deregisterAttesters(0, 1)
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Fast forward until lockup ends.
|
||||
s.fastForward(int(params.DefaultConfig.NotaryLockupLength + 1))
|
||||
s.fastForward(int(params.DefaultConfig.AttesterLockupLength + 1))
|
||||
|
||||
// Notary 0 releases.
|
||||
_, err = s.smc.ReleaseNotary(s.testAccounts[0].txOpts)
|
||||
// Attester 0 releases.
|
||||
_, err = s.smc.ReleaseAttester(s.testAccounts[0].txOpts)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
s.backend.Commit()
|
||||
notary, err := s.smc.NotaryRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
attester, err := s.smc.AttesterRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
if err != nil {
|
||||
t.Errorf("Can't get notary registry info: %v", err)
|
||||
t.Errorf("Can't get attester registry info: %v", err)
|
||||
}
|
||||
if notary.Deposited {
|
||||
t.Errorf("Notary deposit flag should be false after released")
|
||||
if attester.Deposited {
|
||||
t.Errorf("Attester deposit flag should be false after released")
|
||||
}
|
||||
balance, err := s.backend.BalanceAt(ctx, s.testAccounts[0].addr, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Can't get account balance, err: %s", err)
|
||||
}
|
||||
if balance.Cmp(notaryDeposit) < 0 {
|
||||
t.Errorf("Notary did not receive deposit after lock up ends")
|
||||
if balance.Cmp(attesterDeposit) < 0 {
|
||||
t.Errorf("Attester did not receive deposit after lock up ends")
|
||||
}
|
||||
}
|
||||
|
||||
// TestNotaryInstantRelease tests notary releases before lockup ends.
|
||||
func TestNotaryInstantRelease(t *testing.T) {
|
||||
// TestAttesterInstantRelease tests attester releases before lockup ends.
|
||||
func TestAttesterInstantRelease(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
if err := s.registerNotaries(notaryDeposit, 0, 1); err != nil {
|
||||
// Attester 0 registers.
|
||||
if err := s.registerAttesters(attesterDeposit, 0, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := checkNotaryPoolLength(s.smc, big.NewInt(1)); err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
if err := checkAttesterPoolLength(s.smc, big.NewInt(1)); err != nil {
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
|
||||
// Notary 0 deregisters.
|
||||
s.deregisterNotaries(0, 1)
|
||||
if err := checkNotaryPoolLength(s.smc, big.NewInt(0)); err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
// Attester 0 deregisters.
|
||||
s.deregisterAttesters(0, 1)
|
||||
if err := checkAttesterPoolLength(s.smc, big.NewInt(0)); err != nil {
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 tries to release before lockup ends.
|
||||
if _, err := s.smc.ReleaseNotary(s.testAccounts[0].txOpts); err == nil {
|
||||
t.Error("Expected release notary to fail")
|
||||
// Attester 0 tries to release before lockup ends.
|
||||
if _, err := s.smc.ReleaseAttester(s.testAccounts[0].txOpts); err == nil {
|
||||
t.Error("Expected release attester to fail")
|
||||
}
|
||||
s.backend.Commit()
|
||||
notary, err := s.smc.NotaryRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
attester, err := s.smc.AttesterRegistry(&bind.CallOpts{}, s.testAccounts[0].addr)
|
||||
if err != nil {
|
||||
t.Errorf("Can't get notary registry info: %v", err)
|
||||
t.Errorf("Can't get attester registry info: %v", err)
|
||||
}
|
||||
if !notary.Deposited {
|
||||
t.Errorf("Notary deposit flag should be true before released")
|
||||
if !attester.Deposited {
|
||||
t.Errorf("Attester deposit flag should be true before released")
|
||||
}
|
||||
balance, err := s.backend.BalanceAt(ctx, s.testAccounts[0].addr, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if balance.Cmp(notaryDeposit) > 0 {
|
||||
t.Errorf("Notary received deposit before lockup ends")
|
||||
if balance.Cmp(attesterDeposit) > 0 {
|
||||
t.Errorf("Attester received deposit before lockup ends")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCommitteeListsAreDifferent tests different shards have different notary committee.
|
||||
// TestCommitteeListsAreDifferent tests different shards have different attester committee.
|
||||
func TestCommitteeListsAreDifferent(t *testing.T) {
|
||||
const notaryCount = 1000
|
||||
s, _ := newSMCTestHelper(notaryCount)
|
||||
const attesterCount = 1000
|
||||
s, _ := newSMCTestHelper(attesterCount)
|
||||
|
||||
// Register 1000 notaries to s.smc.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1000)
|
||||
// Register 1000 attesters to s.smc.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1000)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1000))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1000))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Compare sampled first 5 notaries of shard 0 to shard 1, they should not be identical.
|
||||
// Compare sampled first 5 attesters of shard 0 to shard 1, they should not be identical.
|
||||
for i := 0; i < 5; i++ {
|
||||
addr0, _ := s.smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
addr1, _ := s.smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(1))
|
||||
addr0, _ := s.smc.GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
addr1, _ := s.smc.GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(1))
|
||||
if addr0 == addr1 {
|
||||
t.Errorf("Shard 0 committee list is identical to shard 1's committee list")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetCommitteeWithNonMember tests unregistered notary tries to be in the committee.
|
||||
// TestGetCommitteeWithNonMember tests unregistered attester tries to be in the committee.
|
||||
func TestGetCommitteeWithNonMember(t *testing.T) {
|
||||
const notaryCount = 11
|
||||
s, _ := newSMCTestHelper(notaryCount)
|
||||
const attesterCount = 11
|
||||
s, _ := newSMCTestHelper(attesterCount)
|
||||
|
||||
// Register 10 notaries to s.smc, leave 1 address free.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 10)
|
||||
// Register 10 attesters to s.smc, leave 1 address free.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 10)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(10))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(10))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Verify the unregistered account is not in the notary pool list.
|
||||
// Verify the unregistered account is not in the attester pool list.
|
||||
for i := 0; i < 10; i++ {
|
||||
addr, _ := s.smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
addr, _ := s.smc.GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
if s.testAccounts[10].addr == addr {
|
||||
t.Errorf("Account %s is not a notary", s.testAccounts[10].addr.String())
|
||||
t.Errorf("Account %s is not a attester", s.testAccounts[10].addr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetCommitteeWithinSamePeriod tests notary registers and samples within the same period.
|
||||
// TestGetCommitteeWithinSamePeriod tests attester registers and samples within the same period.
|
||||
func TestGetCommitteeWithinSamePeriod(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
|
||||
// Notary 0 registers.
|
||||
err := s.registerNotaries(notaryDeposit, 0, 1)
|
||||
// Attester 0 registers.
|
||||
err := s.registerAttesters(attesterDeposit, 0, 1)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(1))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(1))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 samples for itself within the same period after registration.
|
||||
sampledAddr, _ := s.smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
// Attester 0 samples for itself within the same period after registration.
|
||||
sampledAddr, _ := s.smc.GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
if s.testAccounts[0].addr != sampledAddr {
|
||||
t.Errorf("Unable to sample notary address within same period of registration, got addr: %v", sampledAddr)
|
||||
t.Errorf("Unable to sample attester address within same period of registration, got addr: %v", sampledAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetCommitteeAfterDeregisters tests notary tries to be in committee after deregistered.
|
||||
// TestGetCommitteeAfterDeregisters tests attester tries to be in committee after deregistered.
|
||||
func TestGetCommitteeAfterDeregisters(t *testing.T) {
|
||||
const notaryCount = 10
|
||||
s, _ := newSMCTestHelper(notaryCount)
|
||||
const attesterCount = 10
|
||||
s, _ := newSMCTestHelper(attesterCount)
|
||||
|
||||
// Register 10 notaries to s.smc.
|
||||
err := s.registerNotaries(notaryDeposit, 0, notaryCount)
|
||||
// Register 10 attesters to s.smc.
|
||||
err := s.registerAttesters(attesterDeposit, 0, attesterCount)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to release notary: %v", err)
|
||||
t.Errorf("Failed to release attester: %v", err)
|
||||
}
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(10))
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(10))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Deregister notary 0 from s.smc.
|
||||
s.deregisterNotaries(0, 1)
|
||||
err = checkNotaryPoolLength(s.smc, big.NewInt(9))
|
||||
// Deregister attester 0 from s.smc.
|
||||
s.deregisterAttesters(0, 1)
|
||||
err = checkAttesterPoolLength(s.smc, big.NewInt(9))
|
||||
if err != nil {
|
||||
t.Errorf("Notary pool length mismatched: %v", err)
|
||||
t.Errorf("Attester pool length mismatched: %v", err)
|
||||
}
|
||||
|
||||
// Verify degistered notary 0 is not in the notary pool list.
|
||||
// Verify degistered attester 0 is not in the attester pool list.
|
||||
for i := 0; i < 10; i++ {
|
||||
addr, _ := s.smc.GetNotaryInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
addr, _ := s.smc.GetAttesterInCommittee(&bind.CallOpts{}, big.NewInt(0))
|
||||
if s.testAccounts[0].addr == addr {
|
||||
t.Errorf("Account %s is not a notary", s.testAccounts[0].addr.String())
|
||||
t.Errorf("Account %s is not a attester", s.testAccounts[0].addr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -612,11 +612,11 @@ func TestAddHeadersAtWrongPeriod(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubmitVote tests notary submit votes in normal condition.
|
||||
// TestSubmitVote tests attester submit votes in normal condition.
|
||||
func TestSubmitVote(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
// Notary 0 registers.
|
||||
if err := s.registerNotaries(notaryDeposit, 0, 1); err != nil {
|
||||
// Attester 0 registers.
|
||||
if err := s.registerAttesters(attesterDeposit, 0, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
@@ -630,26 +630,26 @@ func TestSubmitVote(t *testing.T) {
|
||||
t.Errorf("Proposer adds header failed: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 votes on header.
|
||||
// Attester 0 votes on header.
|
||||
c, err := s.smc.GetVoteCount(&bind.CallOpts{}, shard0)
|
||||
if err != nil {
|
||||
t.Errorf("Get notary vote count failed: %v", err)
|
||||
t.Errorf("Get attester vote count failed: %v", err)
|
||||
}
|
||||
if c.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Errorf("Incorrect notary vote count, want: 0, got: %v", c)
|
||||
t.Errorf("Incorrect attester vote count, want: 0, got: %v", c)
|
||||
}
|
||||
|
||||
// Notary votes on the header that was submitted.
|
||||
// Attester votes on the header that was submitted.
|
||||
err = s.submitVote(&s.testAccounts[0], shard0, period1, index0, 'A')
|
||||
if err != nil {
|
||||
t.Fatalf("Notary submits vote failed: %v", err)
|
||||
t.Fatalf("Attester submits vote failed: %v", err)
|
||||
}
|
||||
c, err = s.smc.GetVoteCount(&bind.CallOpts{}, shard0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if c.Cmp(big.NewInt(1)) != 0 {
|
||||
t.Errorf("Incorrect notary vote count, want: 1, got: %v", c)
|
||||
t.Errorf("Incorrect attester vote count, want: 1, got: %v", c)
|
||||
}
|
||||
|
||||
// Check header's approved with the current period, should be period 0.
|
||||
@@ -663,11 +663,11 @@ func TestSubmitVote(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// TestSubmitVoteTwice tests notary tries to submit same vote twice.
|
||||
// TestSubmitVoteTwice tests attester tries to submit same vote twice.
|
||||
func TestSubmitVoteTwice(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
// Notary 0 registers.
|
||||
if err := s.registerNotaries(notaryDeposit, 0, 1); err != nil {
|
||||
// Attester 0 registers.
|
||||
if err := s.registerAttesters(attesterDeposit, 0, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
@@ -681,25 +681,25 @@ func TestSubmitVoteTwice(t *testing.T) {
|
||||
t.Errorf("Proposer adds header failed: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 votes on header.
|
||||
// Attester 0 votes on header.
|
||||
if err := s.submitVote(&s.testAccounts[0], shard0, period1, index0, 'A'); err != nil {
|
||||
t.Errorf("Notary submits vote failed: %v", err)
|
||||
t.Errorf("Attester submits vote failed: %v", err)
|
||||
}
|
||||
|
||||
// Notary 0 votes on header again, it should fail.
|
||||
// Attester 0 votes on header again, it should fail.
|
||||
if err := s.submitVote(&s.testAccounts[0], shard0, period1, index0, 'A'); err == nil {
|
||||
t.Errorf("notary voting twice should have failed")
|
||||
t.Errorf("attester voting twice should have failed")
|
||||
}
|
||||
|
||||
// Check notary's vote count is correct in shard.
|
||||
// Check attester's vote count is correct in shard.
|
||||
c, _ := s.smc.GetVoteCount(&bind.CallOpts{}, shard0)
|
||||
if c.Cmp(big.NewInt(1)) != 0 {
|
||||
t.Errorf("Incorrect notary vote count, want: 1, got: %v", c)
|
||||
t.Errorf("Incorrect attester vote count, want: 1, got: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubmitVoteByNonEligibleNotary tests a non-eligible notary tries to submit vote.
|
||||
func TestSubmitVoteByNonEligibleNotary(t *testing.T) {
|
||||
// TestSubmitVoteByNonEligibleAttester tests a non-eligible attester tries to submit vote.
|
||||
func TestSubmitVoteByNonEligibleAttester(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
s.fastForward(1)
|
||||
|
||||
@@ -712,24 +712,24 @@ func TestSubmitVoteByNonEligibleNotary(t *testing.T) {
|
||||
t.Errorf("Proposer adds header failed: %v", err)
|
||||
}
|
||||
|
||||
// Unregistered Notary 0 votes on header, it should fail.
|
||||
// Unregistered Attester 0 votes on header, it should fail.
|
||||
err = s.submitVote(&s.testAccounts[0], shard0, period1, index0, 'A')
|
||||
if err == nil {
|
||||
t.Errorf("Non registered notary submits vote should have failed")
|
||||
t.Errorf("Non registered attester submits vote should have failed")
|
||||
}
|
||||
|
||||
// Check notary's vote count is correct in shard.
|
||||
// Check attester's vote count is correct in shard.
|
||||
c, _ := s.smc.GetVoteCount(&bind.CallOpts{}, shard0)
|
||||
if c.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Errorf("Incorrect notary vote count, want: 0, got: %v", c)
|
||||
t.Errorf("Incorrect attester vote count, want: 0, got: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubmitVoteWithOutAHeader tests a notary tries to submit vote before header gets added.
|
||||
// TestSubmitVoteWithOutAHeader tests a attester tries to submit vote before header gets added.
|
||||
func TestSubmitVoteWithOutAHeader(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
// Notary 0 registers.
|
||||
if err := s.registerNotaries(notaryDeposit, 0, 1); err != nil {
|
||||
// Attester 0 registers.
|
||||
if err := s.registerAttesters(attesterDeposit, 0, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
@@ -740,23 +740,23 @@ func TestSubmitVoteWithOutAHeader(t *testing.T) {
|
||||
index0 := big.NewInt(0)
|
||||
s.testAccounts[0].txOpts.Value = big.NewInt(0)
|
||||
|
||||
// Notary 0 votes on header, it should fail because no header has added.
|
||||
// Attester 0 votes on header, it should fail because no header has added.
|
||||
if err := s.submitVote(&s.testAccounts[0], shard0, period1, index0, 'A'); err == nil {
|
||||
t.Errorf("Notary votes should have failed due to missing header")
|
||||
t.Errorf("Attester votes should have failed due to missing header")
|
||||
}
|
||||
|
||||
// Check notary's vote count is correct in shard
|
||||
// Check attester's vote count is correct in shard
|
||||
c, _ := s.smc.GetVoteCount(&bind.CallOpts{}, shard0)
|
||||
if c.Cmp(big.NewInt(0)) != 0 {
|
||||
t.Errorf("Incorrect notary vote count, want: 1, got: %v", c)
|
||||
t.Errorf("Incorrect attester vote count, want: 1, got: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubmitVoteWithInvalidArgs tests notary submits vote using wrong chunkroot and period.
|
||||
// TestSubmitVoteWithInvalidArgs tests attester submits vote using wrong chunkroot and period.
|
||||
func TestSubmitVoteWithInvalidArgs(t *testing.T) {
|
||||
s, _ := newSMCTestHelper(1)
|
||||
// Notary 0 registers.
|
||||
if err := s.registerNotaries(notaryDeposit, 0, 1); err != nil {
|
||||
// Attester 0 registers.
|
||||
if err := s.registerAttesters(attesterDeposit, 0, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s.fastForward(1)
|
||||
@@ -770,14 +770,14 @@ func TestSubmitVoteWithInvalidArgs(t *testing.T) {
|
||||
t.Errorf("Proposer adds header failed: %v", err)
|
||||
}
|
||||
|
||||
// Notary voting with incorrect period.
|
||||
// Attester voting with incorrect period.
|
||||
period2 := big.NewInt(2)
|
||||
if err := s.submitVote(&s.testAccounts[0], shard0, period2, index0, 'A'); err == nil {
|
||||
t.Errorf("Notary votes should have failed due to incorrect period")
|
||||
t.Errorf("Attester votes should have failed due to incorrect period")
|
||||
}
|
||||
|
||||
// Notary voting with incorrect chunk root.
|
||||
// Attester voting with incorrect chunk root.
|
||||
if err := s.submitVote(&s.testAccounts[0], shard0, period2, index0, 'B'); err == nil {
|
||||
t.Errorf("Notary votes should have failed due to incorrect chunk root")
|
||||
t.Errorf("Attester votes should have failed due to incorrect chunk root")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Registry describes the Notary Registry in the SMC.
|
||||
// Registry describes the Attester Registry in the SMC.
|
||||
type Registry struct {
|
||||
DeregisteredPeriod *big.Int
|
||||
PoolIndex *big.Int
|
||||
|
||||
@@ -6,9 +6,9 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/client/node",
|
||||
visibility = ["//client:__subpackages__"],
|
||||
deps = [
|
||||
"//client/attester:go_default_library",
|
||||
"//client/database:go_default_library",
|
||||
"//client/mainchain:go_default_library",
|
||||
"//client/notary:go_default_library",
|
||||
"//client/observer:go_default_library",
|
||||
"//client/params:go_default_library",
|
||||
"//client/proposer:go_default_library",
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/prysmaticlabs/prysm/client/attester"
|
||||
"github.com/prysmaticlabs/prysm/client/database"
|
||||
"github.com/prysmaticlabs/prysm/client/mainchain"
|
||||
"github.com/prysmaticlabs/prysm/client/notary"
|
||||
"github.com/prysmaticlabs/prysm/client/observer"
|
||||
"github.com/prysmaticlabs/prysm/client/params"
|
||||
"github.com/prysmaticlabs/prysm/client/proposer"
|
||||
@@ -199,7 +199,7 @@ func (s *ShardEthereum) registerTXPool(actor string) error {
|
||||
return s.services.RegisterService(pool)
|
||||
}
|
||||
|
||||
// Registers the actor according to CLI flags. Either notary/proposer/observer.
|
||||
// Registers the actor according to CLI flags. Either attester/proposer/observer.
|
||||
func (s *ShardEthereum) registerActorService(config *params.Config, actor string, shardID int) error {
|
||||
var shardp2p *p2p.Server
|
||||
if err := s.services.FetchService(&shardp2p); err != nil {
|
||||
@@ -221,10 +221,10 @@ func (s *ShardEthereum) registerActorService(config *params.Config, actor string
|
||||
}
|
||||
|
||||
switch actor {
|
||||
case "notary":
|
||||
not, err := notary.NewNotary(config, client, shardp2p, shardChainDB)
|
||||
case "attester":
|
||||
not, err := attester.NewAttester(config, client, shardp2p, shardChainDB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not register notary service: %v", err)
|
||||
return fmt.Errorf("could not register attester service: %v", err)
|
||||
}
|
||||
return s.services.RegisterService(not)
|
||||
case "simulator":
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
package notary
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/prysmaticlabs/prysm/client/internal"
|
||||
shardparams "github.com/prysmaticlabs/prysm/client/params"
|
||||
"github.com/prysmaticlabs/prysm/client/types"
|
||||
)
|
||||
|
||||
// Verifies that Notary implements the Actor interface.
|
||||
var _ = types.Actor(&Notary{})
|
||||
|
||||
func TestHasAccountBeenDeregistered(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend, BlockNumber: 1}
|
||||
|
||||
client.SetDepositFlag(true)
|
||||
err := joinNotaryPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAccountInNotaryPool(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend}
|
||||
|
||||
// address should not be in pool initially.
|
||||
b, err := isAccountInNotaryPool(client, client.Account())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b {
|
||||
t.Fatal("account unexpectedly in notary pool")
|
||||
}
|
||||
|
||||
txOpts, _ := client.CreateTXOpts(shardparams.DefaultConfig.NotaryDeposit)
|
||||
if _, err := smc.RegisterNotary(txOpts); err != nil {
|
||||
t.Fatalf("Failed to deposit: %v", err)
|
||||
}
|
||||
client.CommitWithBlock()
|
||||
b, err = isAccountInNotaryPool(client, client.Account())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !b {
|
||||
t.Error("account not in notary pool when expected to be")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinNotaryPool(t *testing.T) {
|
||||
backend, smc := internal.SetupMockClient(t)
|
||||
client := &internal.MockClient{SMC: smc, T: t, Backend: backend}
|
||||
|
||||
// There should be no notary initially.
|
||||
numNotaries, err := smc.NotaryPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(0).Cmp(numNotaries) != 0 {
|
||||
t.Errorf("unexpected number of notaries. Got %d, wanted 0.", numNotaries)
|
||||
}
|
||||
|
||||
client.SetDepositFlag(false)
|
||||
err = joinNotaryPool(client, client)
|
||||
if err == nil {
|
||||
t.Error("joined notary pool while --deposit was not present")
|
||||
}
|
||||
|
||||
client.SetDepositFlag(true)
|
||||
err = joinNotaryPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Now there should be one notary.
|
||||
numNotaries, err = smc.NotaryPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(1).Cmp(numNotaries) != 0 {
|
||||
t.Errorf("unexpected number of notaries. Got %d, wanted 1", numNotaries)
|
||||
}
|
||||
|
||||
// Join while deposited should do nothing.
|
||||
err = joinNotaryPool(client, client)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
numNotaries, err = smc.NotaryPoolLength(&bind.CallOpts{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if big.NewInt(1).Cmp(numNotaries) != 0 {
|
||||
t.Errorf("unexpected number of notaries. Got %d, wanted 1", numNotaries)
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,15 @@ import (
|
||||
|
||||
// DefaultConfig contains default configs for node to use in the sharded universe.
|
||||
var DefaultConfig = &Config{
|
||||
SMCAddress: common.HexToAddress("0x0"),
|
||||
PeriodLength: 5,
|
||||
NotaryDeposit: new(big.Int).Exp(big.NewInt(10), big.NewInt(21), nil), // 1000 ETH
|
||||
NotaryLockupLength: 16128,
|
||||
ProposerLockupLength: 48,
|
||||
NotaryCommitteeSize: 135,
|
||||
NotaryQuorumSize: 90,
|
||||
NotaryChallengePeriod: 25,
|
||||
CollationSizeLimit: int64(math.Pow(float64(2), float64(20))),
|
||||
SMCAddress: common.HexToAddress("0x0"),
|
||||
PeriodLength: 5,
|
||||
AttesterDeposit: new(big.Int).Exp(big.NewInt(10), big.NewInt(21), nil), // 1000 ETH
|
||||
AttesterLockupLength: 16128,
|
||||
ProposerLockupLength: 48,
|
||||
AttesterCommitteeSize: 135,
|
||||
AttesterQuorumSize: 90,
|
||||
AttesterChallengePeriod: 25,
|
||||
CollationSizeLimit: int64(math.Pow(float64(2), float64(20))),
|
||||
}
|
||||
|
||||
// DefaultChainConfig contains default chain configs of an individual shard.
|
||||
@@ -28,15 +28,15 @@ var DefaultChainConfig = &ChainConfig{}
|
||||
|
||||
// Config contains configs for node to participate in the sharded universe.
|
||||
type Config struct {
|
||||
SMCAddress common.Address // SMCAddress is the address of SMC in mainchain.
|
||||
PeriodLength int64 // PeriodLength is num of blocks in period.
|
||||
NotaryDeposit *big.Int // NotaryDeposit is a required deposit size in wei.
|
||||
NotaryLockupLength int64 // NotaryLockupLength to lockup notary deposit from time of deregistration.
|
||||
ProposerLockupLength int64 // ProposerLockupLength to lockup proposer deposit from time of deregistration.
|
||||
NotaryCommitteeSize int64 // NotaryCommitSize sampled per block from the notaries pool per period per shard.
|
||||
NotaryQuorumSize int64 // NotaryQuorumSize votes the collation needs to get accepted to the canonical chain.
|
||||
NotaryChallengePeriod int64 // NotaryChallengePeriod is the duration a notary has to store collations for.
|
||||
CollationSizeLimit int64 // CollationSizeLimit is the maximum size the serialized blobs in a collation can take.
|
||||
SMCAddress common.Address // SMCAddress is the address of SMC in mainchain.
|
||||
PeriodLength int64 // PeriodLength is num of blocks in period.
|
||||
AttesterDeposit *big.Int // AttesterDeposit is a required deposit size in wei.
|
||||
AttesterLockupLength int64 // AttesterLockupLength to lockup attester deposit from time of deregistration.
|
||||
ProposerLockupLength int64 // ProposerLockupLength to lockup proposer deposit from time of deregistration.
|
||||
AttesterCommitteeSize int64 // AttesterCommitSize sampled per block from the attesters pool per period per shard.
|
||||
AttesterQuorumSize int64 // AttesterQuorumSize votes the collation needs to get accepted to the canonical chain.
|
||||
AttesterChallengePeriod int64 // AttesterChallengePeriod is the duration a attester has to store collations for.
|
||||
CollationSizeLimit int64 // CollationSizeLimit is the maximum size the serialized blobs in a collation can take.
|
||||
}
|
||||
|
||||
// ChainConfig contains chain config of an individual shard. Still to be designed.
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNotaryDeposit(t *testing.T) {
|
||||
func TestAttesterDeposit(t *testing.T) {
|
||||
want, err := new(big.Int).SetString("1000000000000000000000", 10) // 1000 ETH
|
||||
if !err {
|
||||
t.Fatalf("Failed to setup test")
|
||||
}
|
||||
if DefaultConfig.NotaryDeposit.Cmp(want) != 0 {
|
||||
t.Errorf("Notary deposit size incorrect. Wanted %d, got %d", want, DefaultConfig.NotaryDeposit)
|
||||
if DefaultConfig.AttesterDeposit.Cmp(want) != 0 {
|
||||
t.Errorf("Attester deposit size incorrect. Wanted %d, got %d", want, DefaultConfig.AttesterDeposit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ func TestPeriodLength(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotaryLockupLength(t *testing.T) {
|
||||
if DefaultConfig.NotaryLockupLength != 16128 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 16128, DefaultConfig.NotaryLockupLength)
|
||||
func TestAttesterLockupLength(t *testing.T) {
|
||||
if DefaultConfig.AttesterLockupLength != 16128 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 16128, DefaultConfig.AttesterLockupLength)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,20 +33,20 @@ func TestProposerLockupLength(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotaryCommitteeSize(t *testing.T) {
|
||||
if DefaultConfig.NotaryCommitteeSize != 135 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 135, DefaultConfig.NotaryCommitteeSize)
|
||||
func TestAttesterCommitteeSize(t *testing.T) {
|
||||
if DefaultConfig.AttesterCommitteeSize != 135 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 135, DefaultConfig.AttesterCommitteeSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotaryQuorumSize(t *testing.T) {
|
||||
if DefaultConfig.NotaryQuorumSize != 90 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 90, DefaultConfig.NotaryQuorumSize)
|
||||
func TestAttesterQuorumSize(t *testing.T) {
|
||||
if DefaultConfig.AttesterQuorumSize != 90 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 90, DefaultConfig.AttesterQuorumSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotaryChallengePeriod(t *testing.T) {
|
||||
if DefaultConfig.NotaryChallengePeriod != 25 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 25, DefaultConfig.NotaryChallengePeriod)
|
||||
func TestAttesterChallengePeriod(t *testing.T) {
|
||||
if DefaultConfig.AttesterChallengePeriod != 25 {
|
||||
t.Errorf("Shard count incorrect. Wanted %d, got %d", 25, DefaultConfig.AttesterChallengePeriod)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ var log = logrus.WithField("prefix", "simulator")
|
||||
|
||||
// Simulator is a service in a shard node that simulates requests from
|
||||
// remote notes coming over the shardp2p network. For example, if
|
||||
// we are running a proposer service, we would want to simulate notary requests
|
||||
// we are running a proposer service, we would want to simulate attester requests
|
||||
// requests coming to us via a p2p feed. This service will be removed
|
||||
// once p2p internals and end-to-end testing across remote
|
||||
// nodes have been implemented.
|
||||
@@ -50,7 +50,7 @@ func (s *Simulator) Start() {
|
||||
s.requestFeed = s.p2p.Feed(pb.CollationBodyRequest{})
|
||||
|
||||
go s.broadcastTransactions(time.NewTicker(s.delay).C, s.ctx.Done())
|
||||
go s.simulateNotaryRequests(s.client.SMCCaller(), s.client.ChainReader(), time.NewTicker(s.delay).C, s.ctx.Done())
|
||||
go s.simulateAttesterRequests(s.client.SMCCaller(), s.client.ChainReader(), time.NewTicker(s.delay).C, s.ctx.Done())
|
||||
}
|
||||
|
||||
// Stop the main loop for simulator requests.
|
||||
@@ -62,10 +62,10 @@ func (s *Simulator) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// simulateNotaryRequests simulates
|
||||
// simulateAttesterRequests simulates
|
||||
// requests for collation bodies that will be relayed to the appropriate proposer
|
||||
// by the p2p feed layer.
|
||||
func (s *Simulator) simulateNotaryRequests(fetcher mainchain.RecordFetcher, reader mainchain.Reader, delayChan <-chan time.Time, done <-chan struct{}) {
|
||||
func (s *Simulator) simulateAttesterRequests(fetcher mainchain.RecordFetcher, reader mainchain.Reader, delayChan <-chan time.Time, done <-chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
// Makes sure to close this goroutine when the service stops.
|
||||
|
||||
@@ -130,9 +130,9 @@ func TestStartStop(t *testing.T) {
|
||||
}
|
||||
|
||||
// This test uses a faulty chain reader in order to trigger an error
|
||||
// in the simulateNotaryRequests goroutine when reading the block number from
|
||||
// in the simulateAttesterRequests goroutine when reading the block number from
|
||||
// the mainchain via RPC.
|
||||
func TestSimulateNotaryRequests_FaultyReader(t *testing.T) {
|
||||
func TestSimulateAttesterRequests_FaultyReader(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
shardID := 0
|
||||
@@ -150,7 +150,7 @@ func TestSimulateNotaryRequests_FaultyReader(t *testing.T) {
|
||||
doneChan := make(chan struct{})
|
||||
exitRoutine := make(chan bool)
|
||||
go func() {
|
||||
simulator.simulateNotaryRequests(&goodSMCCaller{}, &faultyReader{}, delayChan, doneChan)
|
||||
simulator.simulateAttesterRequests(&goodSMCCaller{}, &faultyReader{}, delayChan, doneChan)
|
||||
<-exitRoutine
|
||||
}()
|
||||
|
||||
@@ -168,9 +168,9 @@ func TestSimulateNotaryRequests_FaultyReader(t *testing.T) {
|
||||
}
|
||||
|
||||
// This test uses a faulty SMCCaller in order to trigger an error
|
||||
// in the simulateNotaryRequests goroutine when reading the collation records
|
||||
// in the simulateAttesterRequests goroutine when reading the collation records
|
||||
// from the SMC.
|
||||
func TestSimulateNotaryRequests_FaultyCaller(t *testing.T) {
|
||||
func TestSimulateAttesterRequests_FaultyCaller(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
shardID := 0
|
||||
@@ -188,7 +188,7 @@ func TestSimulateNotaryRequests_FaultyCaller(t *testing.T) {
|
||||
doneChan := make(chan struct{})
|
||||
exitRoutine := make(chan bool)
|
||||
go func() {
|
||||
simulator.simulateNotaryRequests(&faultySMCCaller{}, &goodReader{}, delayChan, doneChan)
|
||||
simulator.simulateAttesterRequests(&faultySMCCaller{}, &goodReader{}, delayChan, doneChan)
|
||||
<-exitRoutine
|
||||
}()
|
||||
|
||||
@@ -205,10 +205,10 @@ func TestSimulateNotaryRequests_FaultyCaller(t *testing.T) {
|
||||
hook.Reset()
|
||||
}
|
||||
|
||||
// This test checks the proper functioning of the simulateNotaryRequests goroutine
|
||||
// This test checks the proper functioning of the simulateAttesterRequests goroutine
|
||||
// by listening to the requestSent channel which occurs after successful
|
||||
// construction and sending of a request via p2p.
|
||||
func TestSimulateNotaryRequests(t *testing.T) {
|
||||
func TestSimulateAttesterRequests(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
shardID := 0
|
||||
@@ -229,7 +229,7 @@ func TestSimulateNotaryRequests(t *testing.T) {
|
||||
smcCaller := &goodSMCCaller{}
|
||||
|
||||
go func() {
|
||||
simulator.simulateNotaryRequests(smcCaller, &goodReader{}, delayChan, doneChan)
|
||||
simulator.simulateAttesterRequests(smcCaller, &goodReader{}, delayChan, doneChan)
|
||||
<-exitRoutine
|
||||
}()
|
||||
|
||||
@@ -246,7 +246,7 @@ func TestSimulateNotaryRequests(t *testing.T) {
|
||||
hook.Reset()
|
||||
}
|
||||
|
||||
func TestSimulateNotaryRequests_previousPeriod(t *testing.T) {
|
||||
func TestSimulateAttesterRequests_previousPeriod(t *testing.T) {
|
||||
tests := []struct {
|
||||
want int64
|
||||
blockNumber int64
|
||||
@@ -287,7 +287,7 @@ func TestSimulateNotaryRequests_previousPeriod(t *testing.T) {
|
||||
reader := &goodReader{blockNumber: tt.blockNumber}
|
||||
|
||||
go func() {
|
||||
simulator.simulateNotaryRequests(smcCaller, reader, delayChan, doneChan)
|
||||
simulator.simulateAttesterRequests(smcCaller, reader, delayChan, doneChan)
|
||||
<-exitRoutine
|
||||
}()
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func RespondCollationBody(req p2p.Message, collationFetcher types.CollationFetch
|
||||
// RequestCollationBody fetches a collation header record submitted to the SMC for
|
||||
// a shardID, period pair and constructs a p2p collationBodyRequest that will
|
||||
// then be relayed to the appropriate proposer that submitted the collation header.
|
||||
// In production, this will be done within a notary service.
|
||||
// In production, this will be done within a attester service.
|
||||
func RequestCollationBody(fetcher mainchain.RecordFetcher, shardID *big.Int, period *big.Int) (*pb.CollationBodyRequest, error) {
|
||||
|
||||
record, err := fetcher.CollationRecords(&bind.CallOpts{}, shardID, period)
|
||||
|
||||
@@ -202,7 +202,7 @@ func TestCollationBodyResponse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructNotaryRequest(t *testing.T) {
|
||||
func TestConstructAttesterRequest(t *testing.T) {
|
||||
|
||||
backend, smc := setup(t)
|
||||
node := &mockNode{smc: smc, t: t, Backend: backend}
|
||||
@@ -244,22 +244,22 @@ func TestConstructNotaryRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
if nilRequest != nil {
|
||||
t.Errorf("constructNotaryRequest should return nil for an inexistent collation header. got: %v", err)
|
||||
t.Errorf("constructAttesterRequest should return nil for an inexistent collation header. got: %v", err)
|
||||
}
|
||||
|
||||
if common.BytesToHash(request.ChunkRoot).Hex() != chunkRoot.Hex() {
|
||||
t.Errorf("Chunk root from notary request incorrect. want: %v, got: %v", chunkRoot.Hex(), common.BytesToHash(request.ChunkRoot).Hex())
|
||||
t.Errorf("Chunk root from attester request incorrect. want: %v, got: %v", chunkRoot.Hex(), common.BytesToHash(request.ChunkRoot).Hex())
|
||||
}
|
||||
|
||||
if common.BytesToAddress(request.ProposerAddress).Hex() != proposerAddress.Hex() {
|
||||
t.Errorf("Proposer address from notary request incorrect. want: %v, got: %v", proposerAddress.Hex(), common.BytesToAddress(request.ProposerAddress).Hex())
|
||||
t.Errorf("Proposer address from attester request incorrect. want: %v, got: %v", proposerAddress.Hex(), common.BytesToAddress(request.ProposerAddress).Hex())
|
||||
}
|
||||
|
||||
if shardID.Uint64() != request.ShardId {
|
||||
t.Errorf("ShardID from notary request incorrect. want: %d, got: %d", shardID.Uint64(), request.ShardId)
|
||||
t.Errorf("ShardID from attester request incorrect. want: %d, got: %d", shardID.Uint64(), request.ShardId)
|
||||
}
|
||||
|
||||
if request.Period != period.Uint64() {
|
||||
t.Errorf("Proposer address from notary request incorrect. want: %d, got: %d", period.Uint64(), request.Period)
|
||||
t.Errorf("Proposer address from attester request incorrect. want: %d, got: %d", period.Uint64(), request.Period)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ type Node interface {
|
||||
Close()
|
||||
}
|
||||
|
||||
// Actor refers to either a notary, proposer, or observer in the sharding spec.
|
||||
// Actor refers to either a attester, proposer, or observer in the sharding spec.
|
||||
type Actor interface {
|
||||
shared.Service
|
||||
// TODO: will actors have actor-specific methods? To be decided.
|
||||
|
||||
@@ -150,7 +150,7 @@ func (s *Shard) BodyByChunkRoot(chunkRoot *common.Hash) ([]byte, error) {
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// CheckAvailability is used by notaries to confirm a header's data availability.
|
||||
// CheckAvailability is used by attesters to confirm a header's data availability.
|
||||
func (s *Shard) CheckAvailability(header *CollationHeader) (bool, error) {
|
||||
key := dataAvailabilityLookupKey(header.ChunkRoot())
|
||||
availability, err := s.shardDB.Get(key.Bytes())
|
||||
@@ -215,7 +215,7 @@ func (s *Shard) SaveCollation(collation *Collation) error {
|
||||
}
|
||||
|
||||
// SetCanonical sets the collation header as canonical in the shardDB. This is called
|
||||
// after the period is over and over 2/3 notaries voted on the header.
|
||||
// after the period is over and over 2/3 attesters voted on the header.
|
||||
func (s *Shard) SetCanonical(header *CollationHeader) error {
|
||||
if err := s.ValidateShardID(header); err != nil {
|
||||
return err
|
||||
|
||||
@@ -11,12 +11,12 @@ var (
|
||||
// DepositFlag defines whether a node will withdraw ETH from the user's account.
|
||||
DepositFlag = cli.BoolFlag{
|
||||
Name: "deposit",
|
||||
Usage: "To become a notary in a sharding node, " + new(big.Int).Div(shardparams.DefaultConfig.NotaryDeposit, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)).String() + " ETH will be deposited into SMC",
|
||||
Usage: "To become a attester in a sharding node, " + new(big.Int).Div(shardparams.DefaultConfig.AttesterDeposit, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)).String() + " ETH will be deposited into SMC",
|
||||
}
|
||||
// ActorFlag defines the role of the sharding client. Either proposer, notary, or simulator.
|
||||
// ActorFlag defines the role of the sharding client. Either proposer, attester, or simulator.
|
||||
ActorFlag = cli.StringFlag{
|
||||
Name: "actor",
|
||||
Usage: `use the --actor notary or --actor proposer to start a notary or proposer service in the sharding node. If omitted, the sharding node registers an Observer service that simply observes the activity in the sharded network`,
|
||||
Usage: `use the --actor attester or --actor proposer to start a attester or proposer service in the sharding node. If omitted, the sharding node registers an Observer service that simply observes the activity in the sharded network`,
|
||||
}
|
||||
// ShardIDFlag specifies which shard to listen to.
|
||||
ShardIDFlag = cli.IntFlag{
|
||||
|
||||
Reference in New Issue
Block a user