diff --git a/.github/workflows/linuxpackage.yml b/.github/workflows/linuxpackage.yml index 71c2ff477ebe46108a27fd41b6f3ea82721f6bcc..f41bc311ad2a62f6d46222fa38fc7688a7c2a5bc 100644 --- a/.github/workflows/linuxpackage.yml +++ b/.github/workflows/linuxpackage.yml @@ -3,7 +3,7 @@ name: Linux package on: push: tags: - - 'v*.*.*' + - "v*.*.*" jobs: build: runs-on: ubuntu-latest @@ -30,7 +30,7 @@ jobs: sudo apt-get -yqq install libpq-dev build-essential gem install --no-document fpm fpm --version - + make bor cat > bor.service <<- "EOF" @@ -39,8 +39,7 @@ jobs: [Service] WorkingDirectory=/etc/bor/ EnvironmentFile=/etc/bor/metadata - ExecStartPre=/bin/mkdir -p /var/log/matic-logs/ - ExecStart=/bin/bash -c "/usr/bin/bor --datadir /etc/bor/dataDir --port '30303' --rpc --rpcaddr '0.0.0.0' --rpcvhosts '*' --rpccorsdomain '*' --rpcport '8545' --ipcpath /etc/bor/geth.ipc --rpcapi 'bor,db,eth,net,web3,txpool' --networkid ${NETWORK_ID} --gasprice '0' --keystore /etc/bor/dataDir/keystore --unlock ${VALIDATOR_ADDRESS} --password /etc/bor/dataDir/password.txt --allow-insecure-unlock --maxpeers 150 --mine > /var/log/matic-logs/bor.log 2>&1" + ExecStart=/bin/bash -c "/usr/bin/bor --datadir /etc/bor/dataDir --port '30303' --rpc --rpcaddr '0.0.0.0' --rpcvhosts '*' --rpccorsdomain '*' --rpcport '8545' --ipcpath /etc/bor/bor.ipc --rpcapi 'db,eth,net,web3,txpool,bor' --networkid ${NETWORK_ID} --miner.gaslimit '20000000' --txpool.nolocals --txpool.accountslots '128' --txpool.globalslots '20000' --txpool.lifetime '0h16m0s' --keystore /etc/bor/dataDir/keystore --unlock ${VALIDATOR_ADDRESS} --password /etc/bor/dataDir/password.txt --allow-insecure-unlock --maxpeers 150 --mine" Type=simple User=root EOF @@ -60,7 +59,7 @@ jobs: bor.service=/etc/systemd/system/ \ build/bin/bor=/usr/bin/ \ metadata=/etc/bor/ - + mkdir packages-v${{ env.RELEASE_VERSION }} mv matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb packages-v${{ env.RELEASE_VERSION }}/ @@ -75,14 +74,14 @@ jobs: AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_REGION: 'us-east-1' # optional: defaults to us-east-1 - SOURCE_DIR: 'packages-v${{ env.RELEASE_VERSION }}' - DEST_DIR: 'v${{ env.RELEASE_VERSION }}' + AWS_REGION: "us-east-1" # optional: defaults to us-east-1 + SOURCE_DIR: "packages-v${{ env.RELEASE_VERSION }}" + DEST_DIR: "v${{ env.RELEASE_VERSION }}" - name: Slack Notification uses: rtCamp/action-slack-notify@v2.0.0 env: SLACK_CHANNEL: code-releases SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_TITLE: 'New linux package for Bor v${{ env.RELEASE_VERSION }} just got released' - SLACK_MESSAGE: 'Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb' + SLACK_TITLE: "New linux package for Bor v${{ env.RELEASE_VERSION }} just got released" + SLACK_MESSAGE: "Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb" diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index dfcc5ac4bf16735e3d20b8b1cfcd0e07b59074f5..66005b04e986024055d5332190a9dd6a71b37002 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -41,11 +41,11 @@ import ( "sync" "time" + pcsc "github.com/gballet/go-libpcsclite" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/event" "github.com/maticnetwork/bor/log" - pcsc "github.com/gballet/go-libpcsclite" ) // Scheme is the URI prefix for smartcard wallets. diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index 3d0be4728ea2161a4b24c8174efcb77c84c7feef..7f0a8df4ac9a7fb4f636bcff734ed50f86d58b94 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -25,8 +25,8 @@ import ( "crypto/sha512" "fmt" - "github.com/maticnetwork/bor/crypto" pcsc "github.com/gballet/go-libpcsclite" + "github.com/maticnetwork/bor/crypto" "github.com/wsddn/go-ecdh" "golang.org/x/crypto/pbkdf2" "golang.org/x/text/unicode/norm" diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 540bcc1a60dffe9e528545c62529387c1c523d70..6b986ff946c34a4d3b447a91111944947ae21f28 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -33,13 +33,13 @@ import ( "sync" "time" + pcsc "github.com/gballet/go-libpcsclite" ethereum "github.com/maticnetwork/bor" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/log" - pcsc "github.com/gballet/go-libpcsclite" "github.com/status-im/keycard-go/derivationpath" ) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index a80eff5a93a95e5b96a4792f46de5b9419701f5a..e742e49fe01b3818d5f62d3baef15f706e94b3bf 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -23,10 +23,10 @@ import ( "sync/atomic" "time" + "github.com/karalabe/usb" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/event" "github.com/maticnetwork/bor/log" - "github.com/karalabe/usb" ) // LedgerScheme is the protocol scheme prefixing account and wallet URLs. diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index f88501e32f503c3f471f5917fe228486daf784ac..49c71cb0283b1550bf035c57c0c3a4f4e5afc9f7 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -27,13 +27,13 @@ import ( "io" "math/big" + "github.com/golang/protobuf/proto" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/accounts/usbwallet/trezor" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/common/hexutil" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/log" - "github.com/golang/protobuf/proto" ) // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 09a140a756441555a170fa8a9b3b62f1cab23a2f..29f7cf661e9c8291665584b1b3cf273abb8e8d26 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -25,13 +25,13 @@ import ( "sync" "time" + "github.com/karalabe/usb" ethereum "github.com/maticnetwork/bor" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/log" - "github.com/karalabe/usb" ) // Maximum time between wallet health checks to detect USB unplugs. diff --git a/cmd/bor/chaincmd.go b/cmd/bor/chaincmd.go index bbb8792a16e83879cb37f70bc92e6561a7eb79e7..83d3261566ec92a157dde9adce7cee4c6fcff5ba 100644 --- a/cmd/bor/chaincmd.go +++ b/cmd/bor/chaincmd.go @@ -64,6 +64,7 @@ It expects the genesis file as argument.`, ArgsUsage: "<filename> (<filename 2> ... <filename N>) <genesisPath>", Flags: []cli.Flag{ utils.DataDirFlag, + utils.HeimdallURLFlag, utils.CacheFlag, utils.SyncModeFlag, utils.GCModeFlag, diff --git a/cmd/bor/config.go b/cmd/bor/config.go index 4929d826eb0be37d7b9cec6c3f56d8130a33ac4e..9202fec7c4daebd0b9775f94d19689979466101c 100644 --- a/cmd/bor/config.go +++ b/cmd/bor/config.go @@ -151,7 +151,7 @@ func enableWhisper(ctx *cli.Context) bool { func makeFullNode(ctx *cli.Context) *node.Node { stack, cfg := makeConfigNode(ctx) - cfg.Eth.HeimdallURL = ctx.String(utils.HeimdallURLFlag.Name) + cfg.Eth.HeimdallURL = ctx.GlobalString(utils.HeimdallURLFlag.Name) log.Info("Connecting to heimdall service on...", "heimdallURL", cfg.Eth.HeimdallURL) utils.RegisterEthService(stack, &cfg.Eth) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 695005f0907af8c41a6c6bf5c53c1644cad8cc53..e431c17dd5b5bd69cc255db95c4c6a90cf924b26 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -111,6 +111,7 @@ func (w *wizard) makeGenesis() { Period: 1, ProducerDelay: 5, Sprint: 60, + BackupMultiplier: 1, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fa0aa9bf163027368bad09af0375bb4f6687c11f..78a70beabeba715c8758671bdbd8bd9f2295b669 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1694,7 +1694,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai if config.Clique != nil { engine = clique.New(config.Clique, chainDb) } else if config.Bor != nil { - cfg := ð.Config{Genesis: genesis} + cfg := ð.Config{Genesis: genesis, HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name)} workspace, err := ioutil.TempDir("", "console-tester-") if err != nil { Fatalf("failed to create temporary keystore: %v", err) diff --git a/consensus/bor/api.go b/consensus/bor/api.go index 98f7c46b6e615f3adc7625b0c7699cfdc189fc85..5af1ddbc39c2b6acd3c0531b71c3ba05d6e70d75 100644 --- a/consensus/bor/api.go +++ b/consensus/bor/api.go @@ -17,17 +17,33 @@ package bor import ( + "encoding/hex" + "math" + "math/big" + "strconv" + "sync" + + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus" "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/rpc" + "github.com/xsleonard/go-merkle" + "golang.org/x/crypto/sha3" +) + +var ( + // MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash + MaxCheckpointLength = uint64(math.Pow(2, 15)) ) // API is a user facing RPC API to allow controlling the signer and voting // mechanisms of the proof-of-authority scheme. type API struct { - chain consensus.ChainReader - bor *Bor + chain consensus.ChainReader + bor *Bor + rootHashCache *lru.ARCCache } // GetSnapshot retrieves the state snapshot at a given block. @@ -105,3 +121,71 @@ func (api *API) GetCurrentValidators() ([]*Validator, error) { } return snap.ValidatorSet.Validators, nil } + +// GetRootHash returns the merkle root of the start to end block headers +func (api *API) GetRootHash(start uint64, end uint64) (string, error) { + if err := api.initializeRootHashCache(); err != nil { + return "", err + } + key := getRootHashKey(start, end) + if root, known := api.rootHashCache.Get(key); known { + return root.(string), nil + } + length := uint64(end - start + 1) + if length > MaxCheckpointLength { + return "", &MaxCheckpointLengthExceededError{start, end} + } + currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64() + if start > end || end > currentHeaderNumber { + return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber} + } + blockHeaders := make([]*types.Header, end-start+1) + wg := new(sync.WaitGroup) + concurrent := make(chan bool, 20) + for i := start; i <= end; i++ { + wg.Add(1) + concurrent <- true + go func(number uint64) { + blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number)) + <-concurrent + wg.Done() + }(i) + } + wg.Wait() + close(concurrent) + + headers := make([][32]byte, nextPowerOfTwo(length)) + for i := 0; i < len(blockHeaders); i++ { + blockHeader := blockHeaders[i] + header := crypto.Keccak256(appendBytes32( + blockHeader.Number.Bytes(), + new(big.Int).SetUint64(blockHeader.Time).Bytes(), + blockHeader.TxHash.Bytes(), + blockHeader.ReceiptHash.Bytes(), + )) + + var arr [32]byte + copy(arr[:], header) + headers[i] = arr + } + + tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true}) + if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil { + return "", err + } + root := hex.EncodeToString(tree.Root().Hash) + api.rootHashCache.Add(key, root) + return root, nil +} + +func (api *API) initializeRootHashCache() error { + var err error + if api.rootHashCache == nil { + api.rootHashCache, err = lru.NewARC(10) + } + return err +} + +func getRootHashKey(start uint64, end uint64) string { + return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10) +} diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index a59fecd2e8f3750ad9fe7fbbb21d808dacf7fc6d..f456dc871c16d10f33c1d31e55a0633393eff96f 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -12,7 +12,6 @@ import ( "math/big" "sort" - "strconv" "strings" "sync" "time" @@ -41,9 +40,6 @@ import ( "golang.org/x/crypto/sha3" ) -const validatorsetABI = `[{"constant":true,"inputs":[{"name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"span","type":"uint256"},{"name":"signer","type":"address"}],"name":"isProducer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newSpan","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"},{"name":"validatorBytes","type":"bytes"},{"name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"span","type":"uint256"},{"name":"signer","type":"address"}],"name":"isValidator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"proposeSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"spanProposalPending","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` -const stateReceiverABI = `[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"states","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getPendingStates","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorSet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isValidatorSetContract","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"stateId","type":"uint256"}],"name":"proposeState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"signer","type":"address"}],"name":"isProducer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"signer","type":"address"}],"name":"isValidator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]` - const ( checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory @@ -105,10 +101,6 @@ var ( // invalid list of validators (i.e. non divisible by 40 bytes). errInvalidSpanValidators = errors.New("invalid validator list on sprint end block") - // errMismatchingSprintValidators is returned if a sprint block contains a - // list of validators different than the one the local node calculated. - errMismatchingSprintValidators = errors.New("mismatching validator list on sprint block") - // errInvalidMixDigest is returned if a block's mix digest is non-zero. errInvalidMixDigest = errors.New("non-zero mix digest") @@ -118,10 +110,6 @@ var ( // errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2. errInvalidDifficulty = errors.New("invalid difficulty") - // errWrongDifficulty is returned if the difficulty of a block doesn't match the - // turn of the signer. - errWrongDifficulty = errors.New("wrong difficulty") - // ErrInvalidTimestamp is returned if the timestamp of a block is lower than // the previous block's timestamp + the minimum block period. ErrInvalidTimestamp = errors.New("invalid timestamp") @@ -129,13 +117,6 @@ var ( // errOutOfRangeChain is returned if an authorization list is attempted to // be modified via out-of-range or non-contiguous headers. errOutOfRangeChain = errors.New("out of range or non-contiguous chain") - - // errUnauthorizedSigner is returned if a header is signed by a non-authorized entity. - errUnauthorizedSigner = errors.New("unauthorized signer") - - // errRecentlySigned is returned if a header is signed by an authorized entity - // that already signed a header recently, thus is temporarily not allowed to. - errRecentlySigned = errors.New("recently signed") ) // SignerFn is a signer callback function to request a header to be signed by a @@ -198,21 +179,18 @@ func encodeSigHeader(w io.Writer, header *types.Header) { } } -// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty -// that a new block should have based on the previous blocks in the chain and the -// current signer. -func CalcDifficulty(snap *Snapshot, signer common.Address, epoch uint64) *big.Int { - return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, epoch)) -} - -// CalcProducerDelay is the producer delay algorithm based on block time. -func CalcProducerDelay(snap *Snapshot, signer common.Address, period uint64, epoch uint64, producerDelay uint64) uint64 { - // if block is epoch start block, proposer will be inturn signer - if (snap.Number+1)%epoch == 0 { - return producerDelay +// CalcProducerDelay is the block delay algorithm based on block time, period, producerDelay and turn-ness of a signer +func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint64 { + // When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`. + // That is to allow time for block propagation in the last sprint + delay := c.Period + if number%c.Sprint == 0 { + delay = c.ProducerDelay } - - return period + if succession > 0 { + delay += uint64(succession) * c.BackupMultiplier + } + return delay } // BorRLP returns the rlp bytes which needs to be signed for the bor @@ -241,10 +219,11 @@ type Bor struct { signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - ethAPI *ethapi.PublicBlockChainAPI - validatorSetABI abi.ABI - stateReceiverABI abi.ABI - HeimdallClient IHeimdallClient + ethAPI *ethapi.PublicBlockChainAPI + GenesisContractsClient *GenesisContractsClient + validatorSetABI abi.ABI + stateReceiverABI abi.ABI + HeimdallClient IHeimdallClient stateDataFeed event.Feed scope event.SubscriptionScope @@ -273,17 +252,18 @@ func New( vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) heimdallClient, _ := NewHeimdallClient(heimdallURL) - + genesisContractsClient := NewGenesisContractsClient(chainConfig, borConfig.ValidatorContract, borConfig.StateReceiverContract, ethAPI) c := &Bor{ - chainConfig: chainConfig, - config: borConfig, - db: db, - ethAPI: ethAPI, - recents: recents, - signatures: signatures, - validatorSetABI: vABI, - stateReceiverABI: sABI, - HeimdallClient: heimdallClient, + chainConfig: chainConfig, + config: borConfig, + db: db, + ethAPI: ethAPI, + recents: recents, + signatures: signatures, + validatorSetABI: vABI, + stateReceiverABI: sABI, + GenesisContractsClient: genesisContractsClient, + HeimdallClient: heimdallClient, } return c @@ -335,12 +315,9 @@ func (c *Bor) verifyHeader(chain consensus.ChainReader, header *types.Header, pa if header.Time > uint64(time.Now().Unix()) { return consensus.ErrFutureBlock } - // Check that the extra-data contains both the vanity and signature - if len(header.Extra) < extraVanity { - return errMissingVanity - } - if len(header.Extra) < extraVanity+extraSeal { - return errMissingSignature + + if err := validateHeaderExtraField(header.Extra); err != nil { + return err } // check extr adata @@ -376,6 +353,18 @@ func (c *Bor) verifyHeader(chain consensus.ChainReader, header *types.Header, pa return c.verifyCascadingFields(chain, header, parents) } +// validateHeaderExtraField validates that the extra-data contains both the vanity and signature. +// header.Extra = header.Vanity + header.ProducerBytes (optional) + header.Seal +func validateHeaderExtraField(extraBytes []byte) error { + if len(extraBytes) < extraVanity { + return errMissingVanity + } + if len(extraBytes) < extraVanity+extraSeal { + return errMissingSignature + } + return nil +} + // verifyCascadingFields verifies all the header fields that are not standalone, // rather depend on a batch of previous headers. The caller may optionally pass // in a batch of parents (ascending order) to avoid looking those up from the @@ -409,8 +398,9 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainReader, header *types.H return err } - // If the block is a sprint end block, verify the validator list - if number%c.config.Sprint == 0 { + // verify the validator list in the last sprint block + if isSprintStart(number, c.config.Sprint) { + parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal] validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength) currentValidators := snap.ValidatorSet.Copy().Validators @@ -419,14 +409,9 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainReader, header *types.H for i, validator := range currentValidators { copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes()) } - - extraSuffix := len(header.Extra) - extraSeal - - // fmt.Println("validatorsBytes ==> verify seal ==> ", hex.EncodeToString(validatorsBytes)) - // fmt.Println("header.Extra ==> verify seal ==> ", hex.EncodeToString(header.Extra[extraVanity:extraSuffix])) - - if !bytes.Equal(header.Extra[extraVanity:extraSuffix], validatorsBytes) { - // return errMismatchingSprintValidators + // len(header.Extra) >= extraVanity+extraSeal has already been validated in validateHeaderExtraField, so this won't result in a panic + if !bytes.Equal(parentValidatorBytes, validatorsBytes) { + return &MismatchingValidatorsError{number - 1, validatorsBytes, parentValidatorBytes} } } @@ -463,7 +448,7 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H // up more headers than allowed to be reorged (chain reinit from a freezer), // consider the checkpoint trusted and snapshot it. // TODO fix this - if number == 0 /* || (number%c.config.Sprint == 0 && (len(headers) > params.ImmutabilityThreshold || chain.GetHeaderByNumber(number-1) == nil)) */ { + if number == 0 { checkpoint := chain.GetHeaderByNumber(number) if checkpoint != nil { // get checkpoint data @@ -568,37 +553,31 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare return err } if !snap.ValidatorSet.HasAddress(signer.Bytes()) { - return errUnauthorizedSigner + // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1 + return &UnauthorizedSignerError{number - 1, signer.Bytes()} } - // check if signer is correct - validators := snap.ValidatorSet.Validators - // proposer will be the last signer if block is not epoch block - proposer := snap.ValidatorSet.GetProposer().Address - if number%c.config.Sprint != 0 { - // proposer = snap.Recents[number-1] + succession, err := snap.GetSignerSuccessionNumber(signer) + if err != nil { + return err } - proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) - signerIndex, _ := snap.ValidatorSet.GetByAddress(signer) - limit := len(validators)/2 + 1 - // temp index - tempIndex := signerIndex - if proposerIndex != tempIndex && limit > 0 { - if tempIndex < proposerIndex { - tempIndex = tempIndex + len(validators) - } + var parent *types.Header + if len(parents) > 0 { // if parents is nil, len(parents) is zero + parent = parents[len(parents)-1] + } else if number > 0 { + parent = chain.GetHeader(header.ParentHash, number-1) + } - if tempIndex-proposerIndex > limit { - return errRecentlySigned - } + if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) { + return &BlockTooSoonError{number, succession} } // Ensure that the difficulty corresponds to the turn-ness of the signer if !c.fakeDiff { - difficulty := snap.inturn(header.Number.Uint64(), signer, c.config.Sprint) + difficulty := snap.Difficulty(signer) if header.Difficulty.Uint64() != difficulty { - return errWrongDifficulty + return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()} } } @@ -620,7 +599,7 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error { } // Set the correct difficulty - header.Difficulty = CalcDifficulty(snap, c.signer, c.config.Sprint) + header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.signer)) // Ensure the extra data has all it's components if len(header.Extra) < extraVanity { @@ -654,7 +633,16 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error { return consensus.ErrUnknownAncestor } - header.Time = parent.Time + CalcProducerDelay(snap, c.signer, c.config.Period, c.config.Sprint, c.config.ProducerDelay) + var succession int + // if signer is not empty + if bytes.Compare(c.signer.Bytes(), common.Address{}.Bytes()) != 0 { + succession, err = snap.GetSignerSuccessionNumber(c.signer) + if err != nil { + return err + } + } + + header.Time = parent.Time + CalcProducerDelay(number, succession, c.config) if header.Time < uint64(time.Now().Unix()) { header.Time = uint64(time.Now().Unix()) } @@ -664,9 +652,7 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error { // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { - // commit span headerNumber := header.Number.Uint64() - if headerNumber%c.config.Sprint == 0 { cx := chainContext{Chain: chain, Bor: c} // check and commit span @@ -674,6 +660,7 @@ func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state log.Error("Error while committing span", "error", err) return } + // commit statees if err := c.CommitStates(state, header, cx); err != nil { log.Error("Error while committing states", "error", err) @@ -689,8 +676,8 @@ func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. func (c *Bor) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { - // commit span - if header.Number.Uint64()%c.config.Sprint == 0 { + headerNumber := header.Number.Uint64() + if headerNumber%c.config.Sprint == 0 { cx := chainContext{Chain: chain, Bor: c} // check and commit span @@ -703,7 +690,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Hea // commit statees if err := c.CommitStates(state, header, cx); err != nil { log.Error("Error while committing states", "error", err) - // return nil, err + return nil, err } } @@ -752,38 +739,19 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan // Bail out if we're unauthorized to sign a block if !snap.ValidatorSet.HasAddress(signer.Bytes()) { - return errUnauthorizedSigner + // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1 + return &UnauthorizedSignerError{number - 1, signer.Bytes()} } - validators := snap.ValidatorSet.Validators - // proposer will be the last signer if block is not epoch block - proposer := snap.ValidatorSet.GetProposer().Address - if number%c.config.Sprint != 0 { - // proposer = snap.Recents[number-1] - } - - proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) - signerIndex, _ := snap.ValidatorSet.GetByAddress(signer) - limit := len(validators)/2 + 1 - - // temp index - tempIndex := signerIndex - if tempIndex < proposerIndex { - tempIndex = tempIndex + len(validators) - } - - if limit > 0 && tempIndex-proposerIndex > limit { - log.Info("Signed recently, must wait for others") - return nil + successionNumber, err := snap.GetSignerSuccessionNumber(signer) + if err != nil { + return err } // Sweet, the protocol permits us to sign the block, wait for our time delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple - wiggle := time.Duration(2*c.config.Period) * time.Second * time.Duration(tempIndex-proposerIndex) - delay += wiggle - - log.Info("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle)) - log.Info("Sealing block with", "number", number, "delay", delay, "headerDifficulty", header.Difficulty, "signer", signer.Hex(), "proposer", proposer.Hex()) + // wiggle was already accounted for in header.Time, this is just for logging + wiggle := time.Duration(successionNumber) * time.Duration(c.config.BackupMultiplier) * time.Second // Sign all the things! sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header)) @@ -797,17 +765,30 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan go func() { select { case <-stop: + log.Debug("Discarding sealing operation for block", "number", number) return case <-time.After(delay): + if wiggle > 0 { + log.Info( + "Sealing out-of-turn", + "number", number, + "wiggle", common.PrettyDuration(wiggle), + "in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(), + ) + } + log.Info( + "Sealing successful", + "number", number, + "delay", delay, + "headerDifficulty", header.Difficulty, + ) } - select { case results <- block.WithSeal(header): default: - log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) + log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header)) } }() - return nil } @@ -819,7 +800,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *t if err != nil { return nil } - return CalcDifficulty(snap, c.signer, c.config.Sprint) + return new(big.Int).SetUint64(snap.Difficulty(c.signer)) } // SealHash returns the hash of a block prior to it being sealed. @@ -843,42 +824,6 @@ func (c *Bor) Close() error { return nil } -// Checks if new span is pending -func (c *Bor) isSpanPending(snapshotNumber uint64) (bool, error) { - blockNr := rpc.BlockNumber(snapshotNumber) - method := "spanProposalPending" - - // get packed data - data, err := c.validatorSetABI.Pack(method) - if err != nil { - log.Error("Unable to pack tx for spanProposalPending", "error", err) - return false, err - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // cancel when we are finished consuming integers - - // call - msgData := (hexutil.Bytes)(data) - toAddress := common.HexToAddress(c.config.ValidatorContract) - gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ - Gas: &gas, - To: &toAddress, - Data: &msgData, - }, blockNr) - if err != nil { - return false, err - } - - var ret0 = new(bool) - if err := c.validatorSetABI.Unpack(ret0, method, result); err != nil { - return false, err - } - - return *ret0, nil -} - // GetCurrentSpan get current span from contract func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) { // block @@ -893,14 +838,10 @@ func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) { return nil, err } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // cancel when we are finished consuming integers - - // call msgData := (hexutil.Bytes)(data) toAddress := common.HexToAddress(c.config.ValidatorContract) gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ + result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{ Gas: &gas, To: &toAddress, Data: &msgData, @@ -943,14 +884,11 @@ func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([ return nil, err } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // cancel when we are finished consuming integers - // call msgData := (hexutil.Bytes)(data) toAddress := common.HexToAddress(c.config.ValidatorContract) gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ + result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{ Gas: &gas, To: &toAddress, Data: &msgData, @@ -990,37 +928,14 @@ func (c *Bor) checkAndCommitSpan( chain core.ChainContext, ) error { headerNumber := header.Number.Uint64() - pending := false - var span *Span = nil - errors := make(chan error) - go func() { - var err error - pending, err = c.isSpanPending(headerNumber - 1) - errors <- err - }() - - go func() { - var err error - span, err = c.GetCurrentSpan(headerNumber - 1) - errors <- err - }() - - var err error - for i := 0; i < 2; i++ { - err = <-errors - if err != nil { - close(errors) - return err - } + span, err := c.GetCurrentSpan(headerNumber - 1) + if err != nil { + return err } - close(errors) - - // commit span if there is new span pending or span is ending or end block is not set - if pending || c.needToCommitSpan(span, headerNumber) { + if c.needToCommitSpan(span, headerNumber) { err := c.fetchAndCommitSpan(span.ID+1, state, header, chain) return err } - return nil } @@ -1049,7 +964,7 @@ func (c *Bor) fetchAndCommitSpan( header *types.Header, chain core.ChainContext, ) error { - response, err := c.HeimdallClient.FetchWithRetry("bor", "span", strconv.FormatUint(newSpanID, 10)) + response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "") if err != nil { return err @@ -1133,13 +1048,10 @@ func (c *Bor) GetPendingStateProposals(snapshotNumber uint64) ([]*big.Int, error return nil, err } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // cancel when we are finished consuming integers - msgData := (hexutil.Bytes)(data) toAddress := common.HexToAddress(c.config.StateReceiverContract) gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ + result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{ Gas: &gas, To: &toAddress, Data: &msgData, @@ -1160,83 +1072,55 @@ func (c *Bor) GetPendingStateProposals(snapshotNumber uint64) ([]*big.Int, error func (c *Bor) CommitStates( state *state.StateDB, header *types.Header, - chain core.ChainContext, + chain chainContext, ) error { - // get pending state proposals - stateIds, err := c.GetPendingStateProposals(header.Number.Uint64() - 1) + number := header.Number.Uint64() + _lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1) if err != nil { return err } - // state ids - if len(stateIds) > 0 { - log.Debug("Found new proposed states", "numberOfStates", len(stateIds)) - } - - method := "commitState" + to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0) + lastStateID := _lastStateID.Uint64() + log.Info( + "Fetching state updates from Heimdall", + "fromID", lastStateID+1, + "to", to.Format(time.RFC3339)) + eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix()) - // itereate through state ids - for _, stateID := range stateIds { - // fetch from heimdall - response, err := c.HeimdallClient.FetchWithRetry("clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10)) - if err != nil { - return err + chainID := c.chainConfig.ChainID.String() + for _, eventRecord := range eventRecords { + if eventRecord.ID <= lastStateID { + continue } - - // get event record - var eventRecord EventRecord - if err := json.Unmarshal(response.Result, &eventRecord); err != nil { - return err - } - - // check if chain id matches with event record - if eventRecord.ChainID != "" && eventRecord.ChainID != c.chainConfig.ChainID.String() { - return fmt.Errorf( - "Chain id proposed state in span, %s, and bor chain id, %s, doesn't match", - eventRecord.ChainID, - c.chainConfig.ChainID, - ) + if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { + log.Error(err.Error()) + break } - log.Info("→ committing new state", - "id", eventRecord.ID, - "contract", eventRecord.Contract, - "data", hex.EncodeToString(eventRecord.Data), - "txHash", eventRecord.TxHash, - "chainID", eventRecord.ChainID, - ) stateData := types.StateData{ Did: eventRecord.ID, Contract: eventRecord.Contract, Data: hex.EncodeToString(eventRecord.Data), TxHash: eventRecord.TxHash, } - go func() { c.stateDataFeed.Send(core.NewStateChangeEvent{StateData: &stateData}) }() - recordBytes, err := rlp.EncodeToBytes(eventRecord) - if err != nil { - return err - } - - // get packed data for commit state - data, err := c.stateReceiverABI.Pack(method, recordBytes) - if err != nil { - log.Error("Unable to pack tx for commitState", "error", err) - return err - } - - // get system message - msg := getSystemMessage(common.HexToAddress(c.config.StateReceiverContract), data) - - // apply message - if err := applyMessage(msg, state, header, c.chainConfig, chain); err != nil { + if err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain); err != nil { return err } + lastStateID++ } + return nil +} +func validateEventRecord(eventRecord *EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error { + // event id should be sequential and event.Time should lie in the range [from, to) + if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) { + return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord} + } return nil } @@ -1249,48 +1133,6 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) { c.HeimdallClient = h } -func (c *Bor) IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool { - header := chain.CurrentHeader() - validators, err := c.GetCurrentValidators(header.Number.Uint64(), header.Number.Uint64()+1) - if err != nil { - log.Error("Failed fetching snapshot", err) - return false - } - - isValidator := false - for _, validator := range validators { - if bytes.Compare(validator.Address.Bytes(), from.Bytes()) == 0 { - isValidator = true - break - } - } - - return isValidator && (isProposeSpanAction(tx, chain.Config().Bor.ValidatorContract) || - isProposeStateAction(tx, chain.Config().Bor.StateReceiverContract)) -} - -func isProposeSpanAction(tx *types.Transaction, validatorContract string) bool { - // keccak256('proposeSpan()').slice(0, 4) - proposeSpanSig, _ := hex.DecodeString("4b0e4d17") - if tx.Data() == nil || len(tx.Data()) < 4 { - return false - } - - return bytes.Compare(proposeSpanSig, tx.Data()[:4]) == 0 && - tx.To().String() == validatorContract -} - -func isProposeStateAction(tx *types.Transaction, stateReceiverContract string) bool { - // keccak256('proposeState(uint256)').slice(0, 4) - proposeStateSig, _ := hex.DecodeString("ede01f17") - if tx.Data() == nil || len(tx.Data()) < 4 { - return false - } - - return bytes.Compare(proposeStateSig, tx.Data()[:4]) == 0 && - tx.To().String() == stateReceiverContract -} - // // Private methods // @@ -1403,3 +1245,7 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) v.UpdateWithChangeSet(changes) return v } + +func isSprintStart(number, sprint uint64) bool { + return number%sprint == 0 +} diff --git a/consensus/bor/bor_test/bor_test.go b/consensus/bor/bor_test/bor_test.go index ce1585f6f2f8788c8b2c1d709b00a706685ee6fd..2994143d12a5f7d28271723d0436b9a0fa564a36 100644 --- a/consensus/bor/bor_test/bor_test.go +++ b/consensus/bor/bor_test/bor_test.go @@ -2,130 +2,269 @@ package bortest import ( "encoding/hex" + "encoding/json" "math/big" "testing" + "time" - "github.com/maticnetwork/bor/common" - "github.com/maticnetwork/bor/consensus/bor" - "github.com/maticnetwork/bor/core/rawdb" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/maticnetwork/bor/consensus/bor" + "github.com/maticnetwork/bor/core/rawdb" "github.com/maticnetwork/bor/core/types" - + "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/mocks" ) -func TestCommitSpan(t *testing.T) { +var ( + spanPath = "bor/span/1" + clerkPath = "clerk/event-record/list" + clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50" +) + +func TestInsertingSpanSizeBlocks(t *testing.T) { init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) chain := init.ethereum.BlockChain() engine := init.ethereum.Engine() _bor := engine.(*bor.Bor) - - // Mock HeimdallClient.FetchWithRetry to return span data from span.json - res, heimdallSpan := loadSpanFromFile(t) - h := &mocks.IHeimdallClient{} - h.On("FetchWithRetry", "bor", "span", "1"). - Return(res, nil). - Times(2) // both FinalizeAndAssemble and chain.InsertChain call HeimdallClient.FetchWithRetry. @todo Investigate this in depth + h, heimdallSpan := getMockedHeimdallClient(t) _bor.SetHeimdallClient(h) db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) - // Build 1st block's header - header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) + // to := int64(block.Header().Time) - statedb, err := chain.State() - if err != nil { - t.Fatalf("%s", err) + // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint + for i := uint64(1); i <= spanSize; i++ { + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) } - _key, _ := hex.DecodeString(privKey) - insertNewBlock(t, _bor, chain, header, statedb, _key) - - assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 2)) - validators, err := _bor.GetCurrentValidators(1, 256) // new span starts at 256 + assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, "")) + validators, err := _bor.GetCurrentValidators(sprintSize, spanSize) // check validator set at the first block of new span if err != nil { t.Fatalf("%s", err) } - assert.Equal(t, len(validators), 3) + assert.Equal(t, 3, len(validators)) for i, validator := range validators { assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes()) assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower) } } -func TestIsValidatorAction(t *testing.T) { +func TestFetchStateSyncEvents(t *testing.T) { init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) chain := init.ethereum.BlockChain() engine := init.ethereum.Engine() _bor := engine.(*bor.Bor) - proposeStateData, _ := hex.DecodeString("ede01f170000000000000000000000000000000000000000000000000000000000000000") - proposeSpanData, _ := hex.DecodeString("4b0e4d17") - var tx *types.Transaction - tx = types.NewTransaction( - 0, - common.HexToAddress(chain.Config().Bor.StateReceiverContract), - big.NewInt(0), 0, big.NewInt(0), - proposeStateData, - ) - assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) - - tx = types.NewTransaction( - 0, - common.HexToAddress(chain.Config().Bor.ValidatorContract), - big.NewInt(0), 0, big.NewInt(0), - proposeSpanData, - ) - assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) + // A. Insert blocks for 0th sprint + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint + for i := uint64(1); i < sprintSize; i++ { + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) + } - res, heimdallSpan := loadSpanFromFile(t) + // B. Before inserting 1st block of the next sprint, mock heimdall deps + // B.1 Mock /bor/span/1 + res, _ := loadSpanFromFile(t) + h := &mocks.IHeimdallClient{} + h.On("FetchWithRetry", spanPath, "").Return(res, nil) + + // B.2 Mock State Sync events + fromID := uint64(1) + // at # sprintSize, events are fetched for [fromID, (block-sprint).Time) + to := int64(chain.GetHeaderByNumber(0).Time) + eventCount := 50 + + sample := getSampleEventRecord(t) + sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to + eventRecords := generateFakeStateSyncEvents(sample, eventCount) + h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil) + _bor.SetHeimdallClient(h) + + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) + + assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, "")) + assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to)) +} + +func TestFetchStateSyncEvents_2(t *testing.T) { + init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) + chain := init.ethereum.BlockChain() + engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + + // Mock /bor/span/1 + res, _ := loadSpanFromFile(t) h := &mocks.IHeimdallClient{} - h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil) + h.On("FetchWithRetry", spanPath, "").Return(res, nil) + + // Mock State Sync events + // at # sprintSize, events are fetched for [fromID, (block-sprint).Time) + fromID := uint64(1) + to := int64(chain.GetHeaderByNumber(0).Time) + sample := getSampleEventRecord(t) + + // First query will be from [id=1, (block-sprint).Time] + // Insert 5 events in this time range + eventRecords := []*bor.EventRecordWithTime{ + buildStateEvent(sample, 1, 3), // id = 1, time = 1 + buildStateEvent(sample, 2, 1), // id = 2, time = 3 + buildStateEvent(sample, 3, 2), // id = 3, time = 2 + // event with id 5 is missing + buildStateEvent(sample, 4, 5), // id = 4, time = 5 + buildStateEvent(sample, 6, 4), // id = 6, time = 4 + } + h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil) _bor.SetHeimdallClient(h) - // Build 1st block's header + // Insert blocks for 0th sprint db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) + for i := uint64(1); i <= sprintSize; i++ { + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) + } + assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, "")) + assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to)) + lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize) + // state 6 was not written + assert.Equal(t, uint64(4), lastStateID.Uint64()) - header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) - statedb, err := chain.State() - if err != nil { - t.Fatalf("%s", err) + // + fromID = uint64(5) + to = int64(chain.GetHeaderByNumber(sprintSize).Time) + eventRecords = []*bor.EventRecordWithTime{ + buildStateEvent(sample, 5, 7), + buildStateEvent(sample, 6, 4), + } + h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil) + for i := sprintSize + 1; i <= spanSize; i++ { + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) + } + assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to)) + lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize) + assert.Equal(t, uint64(6), lastStateID.Uint64()) +} + +func TestOutOfTurnSigning(t *testing.T) { + init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) + chain := init.ethereum.BlockChain() + engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + h, _ := getMockedHeimdallClient(t) + _bor.SetHeimdallClient(h) + + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + + for i := uint64(1); i < spanSize; i++ { + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + insertNewBlock(t, chain, block) } - _key, _ := hex.DecodeString(privKey) - insertNewBlock(t, _bor, chain, header, statedb, _key) + // insert spanSize-th block + // This account is one the out-of-turn validators for 1st (0-indexed) span + signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9" + signerKey, _ := hex.DecodeString(signer) + key, _ = crypto.HexToECDSA(signer) + addr = crypto.PubkeyToAddress(key.PublicKey) + expectedSuccessionNumber := 2 + + block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor) + _, err := chain.InsertChain([]*types.Block{block}) + assert.Equal(t, + *err.(*bor.BlockTooSoonError), + bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber}) + + expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession + header := block.Header() + header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) - + bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor)) + sign(t, header, signerKey) block = types.NewBlockWithHeader(header) + _, err = chain.InsertChain([]*types.Block{block}) + assert.Equal(t, + *err.(*bor.WrongDifficultyError), + bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()}) - var headers []*types.Header - for i := int64(2); i <= 255; i++ { - header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) - headers = append(headers, header) - block = types.NewBlockWithHeader(header) - } - t.Logf("inserting %v headers", len(headers)) - if _, err := chain.InsertHeaderChain(headers, 0); err != nil { - t.Fatalf("%s", err) + header.Difficulty = new(big.Int).SetUint64(expectedDifficulty) + sign(t, header, signerKey) + block = types.NewBlockWithHeader(header) + _, err = chain.InsertChain([]*types.Block{block}) + assert.Nil(t, err) +} + +func TestSignerNotFound(t *testing.T) { + init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) + chain := init.ethereum.BlockChain() + engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + h, _ := getMockedHeimdallClient(t) + _bor.SetHeimdallClient(h) + + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + + // random signer account that is not a part of the validator set + signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b" + signerKey, _ := hex.DecodeString(signer) + key, _ = crypto.HexToECDSA(signer) + addr = crypto.PubkeyToAddress(key.PublicKey) + + block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor) + _, err := chain.InsertChain([]*types.Block{block}) + assert.Equal(t, + *err.(*bor.UnauthorizedSignerError), + bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()}) +} + +func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) { + res, heimdallSpan := loadSpanFromFile(t) + h := &mocks.IHeimdallClient{} + h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil) + h.On( + "FetchStateSyncEvents", + mock.AnythingOfType("uint64"), + mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil) + return h, heimdallSpan +} + +func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime { + events := make([]*bor.EventRecordWithTime, count) + event := *sample + event.ID = 1 + events[0] = &bor.EventRecordWithTime{} + *events[0] = event + for i := 1; i < count; i++ { + event.ID = uint64(i) + event.Time = event.Time.Add(1 * time.Second) + events[i] = &bor.EventRecordWithTime{} + *events[i] = event } + return events +} + +func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime { + event := *sample + event.ID = id + event.Time = time.Unix(timeStamp, 0) + return &event +} - for _, validator := range heimdallSpan.SelectedProducers { - _addr := validator.Address - tx = types.NewTransaction( - 0, - common.HexToAddress(chain.Config().Bor.StateReceiverContract), - big.NewInt(0), 0, big.NewInt(0), - proposeStateData, - ) - assert.True(t, _bor.IsValidatorAction(chain, _addr, tx)) - - tx = types.NewTransaction( - 0, - common.HexToAddress(chain.Config().Bor.ValidatorContract), - big.NewInt(0), 0, big.NewInt(0), - proposeSpanData, - ) - assert.True(t, _bor.IsValidatorAction(chain, _addr, tx)) +func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime { + res := stateSyncEventsPayload(t) + var _eventRecords []*bor.EventRecordWithTime + if err := json.Unmarshal(res.Result, &_eventRecords); err != nil { + t.Fatalf("%s", err) } + _eventRecords[0].Time = time.Unix(1, 0) + return _eventRecords[0] } diff --git a/consensus/bor/bor_test/genesis.json b/consensus/bor/bor_test/genesis.json index 32b9cd5b2aa474f4d6a629a87dec04e5a5f32b3b..ca21f42e1ac5f30cf8bb6a34908b5afe49c796eb 100644 --- a/consensus/bor/bor_test/genesis.json +++ b/consensus/bor/bor_test/genesis.json @@ -11,7 +11,8 @@ "bor": { "period": 1, "producerDelay": 4, - "sprint": 1, + "sprint": 4, + "backupMultiplier": 1, "validatorContract": "0x0000000000000000000000000000000000001000", "stateReceiverContract": "0x0000000000000000000000000000000000001001" } @@ -26,15 +27,15 @@ "alloc": { "0000000000000000000000000000000000001000": { "balance": "0x0", - "code": "0x608060405234801561001057600080fd5b50600436106102115760003560e01c806365b3a1e211610125578063b2472431116100ad578063d0504f891161007c578063d0504f89146106af578063d5b844eb146106cb578063dcf2793a146106e9578063e3b7c9241461071b578063f59cf5651461073957610211565b8063b247243114610612578063b71d7a6914610630578063b7ab4db514610660578063c1b3c9191461067f57610211565b806370ba5707116100f457806370ba57071461055657806398ab2b62146105865780639d11b807146105a4578063ae756451146105d4578063af26aa96146105f257610211565b806365b3a1e2146104c957806366332354146104e8578063687a9bd61461050657806369c49fac1461053857610211565b806335ddfeea116101a85780634b0e4d17116101775780634b0e4d17146104215780634dbc959f1461042b57806355614fcc14610449578063582a8d081461047957806360c8614d146104a957610211565b806335ddfeea1461037357806343ee8213146103a357806344c15cb1146103c157806344d6528f146103f157610211565b806323f2a73f116101e457806323f2a73f146102c55780632de3a180146102f55780632eddf352146103255780633434735f1461035557610211565b8063047a6c5b146102165780630c35b1cb146102485780631270b5741461027957806323c2a2b4146102a9575b600080fd5b610230600480360361022b9190810190612e7e565b61076b565b60405161023f93929190613903565b60405180910390f35b610262600480360361025d9190810190612e7e565b6107c2565b6040516102709291906136c4565b60405180910390f35b610293600480360361028e9190810190612ea7565b61099e565b6040516102a091906136fb565b60405180910390f35b6102c360048036036102be9190810190612f86565b610af6565b005b6102df60048036036102da9190810190612ea7565b611177565b6040516102ec91906136fb565b60405180910390f35b61030f600480360361030a9190810190612d18565b6112cf565b60405161031c9190613716565b60405180910390f35b61033f600480360361033a9190810190612e7e565b611350565b60405161034c91906138b1565b60405180910390f35b61035d611481565b60405161036a91906136a9565b60405180910390f35b61038d60048036036103889190810190612d54565b611499565b60405161039a91906136fb565b60405180910390f35b6103ab611564565b6040516103b89190613716565b60405180910390f35b6103db60048036036103d69190810190612ee3565b61157b565b6040516103e891906138b1565b60405180910390f35b61040b60048036036104069190810190612ea7565b611663565b6040516104189190613896565b60405180910390f35b6104296117cc565b005b610433611828565b60405161044091906138b1565b60405180910390f35b610463600480360361045e9190810190612c9d565b611838565b60405161047091906136fb565b60405180910390f35b610493600480360361048e9190810190612cc6565b611852565b6040516104a09190613716565b60405180910390f35b6104b16118d0565b6040516104c093929190613903565b60405180910390f35b6104d1611944565b6040516104df9291906136c4565b60405180910390f35b6104f0611a34565b6040516104fd91906138b1565b60405180910390f35b610520600480360361051b9190810190612f4a565b611a39565b60405161052f939291906138cc565b60405180910390f35b610540611a9d565b60405161054d91906136fb565b60405180910390f35b610570600480360361056b9190810190612c9d565b611ab4565b60405161057d91906136fb565b60405180910390f35b61058e611ace565b60405161059b9190613716565b60405180910390f35b6105be60048036036105b99190810190612e7e565b611ae5565b6040516105cb91906138b1565b60405180910390f35b6105dc611c16565b6040516105e99190613716565b60405180910390f35b6105fa611c2d565b60405161060993929190613903565b60405180910390f35b61061a611c8e565b60405161062791906138b1565b60405180910390f35b61064a60048036036106459190810190612e7e565b611c94565b60405161065791906138b1565b60405180910390f35b610668611d94565b6040516106769291906136c4565b60405180910390f35b61069960048036036106949190810190612e7e565b611da8565b6040516106a691906138b1565b60405180910390f35b6106c960048036036106c49190810190612dbb565b611dc9565b005b6106d361201f565b6040516106e0919061393a565b60405180910390f35b61070360048036036106fe9190810190612f4a565b612024565b604051610712939291906138cc565b60405180910390f35b610723612088565b60405161073091906138b1565b60405180910390f35b610753600480360361074e9190810190612e7e565b61209a565b60405161076293929190613903565b60405180910390f35b60008060006004600085815260200190815260200160002060000154600460008681526020019081526020016000206001015460046000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107de576107d5611944565b91509150610999565b60006107e984611c94565b9050606060036000838152602001908152602001600020805490506040519080825280602002602001820160405280156108325781602001602082028038833980820191505090505b5090506060600360008481526020019081526020016000208054905060405190808252806020026020018201604052801561087c5781602001602082028038833980820191505090505b50905060008090505b600360008581526020019081526020016000208054905081101561098e576003600085815260200190815260200160002081815481106108c157fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168382815181106108ff57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060036000858152602001908152602001600020818154811061095757fe5b90600052602060002090600302016001015482828151811061097557fe5b6020026020010181815250508080600101915050610885565b508181945094505050505b915091565b6000606060036000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a71578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906109d5565b50505050905060008090505b8151811015610ae9578373ffffffffffffffffffffffffffffffffffffffff16828281518110610aa957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610adc57600192505050610af0565b8080600101915050610a7d565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b4257600080fd5b6000610b4c611828565b90506000811415610b6057610b5f6120c4565b5b610b746001826123f090919063ffffffff16565b8814610bb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bac906137b6565b60405180910390fd5b868611610bf7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bee90613816565b60405180910390fd5b6000805460018989030181610c0857fe5b0614610c49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c40906137f6565b60405180910390fd5b8660046000838152602001908152602001600020600101541115610ca2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9990613776565b60405180910390fd5b6000600460008a81526020019081526020016000206000015414610cfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf2906137d6565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600460008a815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060058890806001815401808255809150509060018203906000526020600020016000909192909190915055506000600260008a815260200190815260200160002081610d969190612a97565b506000600360008a815260200190815260200160002081610db79190612a97565b506060610e0f610e0a87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b8151811015610f83576060610e3e838381518110610e3157fe5b602002602001015161243d565b9050600260008c81526020019081526020016000208054809190600101610e659190612a97565b506040518060600160405280610e8e83600081518110610e8157fe5b602002602001015161251a565b8152602001610eb083600181518110610ea357fe5b602002602001015161251a565b8152602001610ed283600281518110610ec557fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600260008d81526020019081526020016000208381548110610f0957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610e17565b506060610fdb610fd686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b815181101561114f57606061100a838381518110610ffd57fe5b602002602001015161243d565b9050600360008d815260200190815260200160002080548091906001016110319190612a97565b50604051806060016040528061105a8360008151811061104d57fe5b602002602001015161251a565b815260200161107c8360018151811061106f57fe5b602002602001015161251a565b815260200161109e8360028151811061109157fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600360008e815260200190815260200160002083815481106110d557fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fe3565b506000600160006101000a81548160ff02191690831515021790555050505050505050505050565b6000606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561124a578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906111ae565b50505050905060008090505b81518110156112c2578373ffffffffffffffffffffffffffffffffffffffff1682828151811061128257fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112b5576001925050506112c9565b8080600101915050611256565b5060009150505b92915050565b60006002600160f81b84846040516020016112ec93929190613616565b6040516020818303038152906040526040516113089190613653565b602060405180830381855afa158015611325573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506113489190810190612cef565b905092915050565b6000606060026000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611423578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611387565b505050509050600080905060008090505b82518110156114765761146783828151811061144c57fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611434565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b60008060008085905060006021808751816114b057fe5b0402905060008111156114c9576114c687611852565b91505b6000602190505b818111611553576000600182038801519050818801519550806000602081106114f557fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561153a5761153386856112cf565b9350611547565b61154484876112cf565b93505b506021810190506114d0565b508782149450505050509392505050565b6040516115709061367f565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff1610156116565760606115b8868367ffffffffffffffff1660416125ae565b905060006115cf828961263a90919063ffffffff16565b90506115d9612ac9565b6115e38a83611663565b90506115ef8a83611177565b801561162657508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b15611648578194506116458160200151876123f090919063ffffffff16565b95505b50505060418101905061158d565b5081925050509392505050565b61166b612ac9565b606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561173c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906116a0565b50505050905060008090505b81518110156117c4578373ffffffffffffffffffffffffffffffffffffffff1682828151811061177457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156117b7578181815181106117a857fe5b602002602001015192506117c4565b8080600101915050611748565b505092915050565b60006117d6611828565b90506117e28133611177565b6117eb57600080fd5b60001515600160009054906101000a900460ff1615151461180b57600080fd5b60018060006101000a81548160ff02191690831515021790555050565b600061183343611c94565b905090565b600061184b611845611828565b83611177565b9050919050565b60006002600060f81b8360405160200161186d9291906135ea565b6040516020818303038152906040526040516118899190613653565b602060405180830381855afa1580156118a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118c99190810190612cef565b9050919050565b6000806000806118f160016118e3611828565b6123f090919063ffffffff16565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b606080606060016040519080825280602002602001820160405280156119795781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f78160008151811061199e57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606001604051908082528060200260200182016040528015611a0a5781602001602082028038833980820191505090505b509050600a81600081518110611a1c57fe5b60200260200101818152505081819350935050509091565b60ff81565b60036020528160005260406000208181548110611a5257fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000600160009054906101000a900460ff16905090565b6000611ac7611ac1611828565b8361099e565b9050919050565b604051611ada9061366a565b604051809103902081565b6000606060036000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611bb8578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611b1c565b505050509050600080905060008090505b8251811015611c0b57611bfc838281518110611be157fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611bc9565b508092505050919050565b604051611c2290613694565b604051809103902081565b600080600080611c3b611828565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b60005481565b60008060058054905090505b6000811115611d5457611cb1612b00565b6004600060056001850381548110611cc557fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611d2257506000816040015114155b8015611d32575080604001518411155b15611d4557806000015192505050611d8f565b50808060019003915050611ca0565b5060006005805490501115611d8a57600560016005805490500381548110611d7857fe5b90600052602060002001549050611d8f565b600090505b919050565b606080611da0436107c2565b915091509091565b60058181548110611db557fe5b906000526020600020016000915090505481565b6060611ddc611dd78661240f565b61243d565b9050604051611dea9061367f565b6040518091039020611e0f82600081518110611e0257fe5b6020026020010151612744565b8051906020012014611e56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4d90613796565b60405180910390fd5b600260ff16611e7882600181518110611e6b57fe5b602002602001015161251a565b14611eb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eaf90613836565b60405180910390fd5b611f31611ed882600481518110611ecb57fe5b602002602001015161251a565b60001b600285604051611eeb9190613653565b602060405180830381855afa158015611f08573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250611f2b9190810190612cef565b84611499565b611f70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6790613856565b60405180910390fd5b6000611f7a611828565b90506000611f908288805190602001208861157b565b9050611fd46001611fc66003611fb86002611faa88611350565b6127d090919063ffffffff16565b61280a90919063ffffffff16565b6123f090919063ffffffff16565b811015612016576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161200d90613876565b60405180910390fd5b50505050505050565b600281565b6002602052816000526040600020818154811061203d57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006040438161209457fe5b04905090565b60046020528060005260406000206000915090508060000154908060010154908060020154905083565b60406000819055506060806120d7611944565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600460008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506005819080600181540180825580915050906001820390600052602060002001600090919290919091505550600060026000838152602001908152602001600020816121819190612a97565b50600060036000838152602001908152602001600020816121a29190612a97565b5060008090505b83518110156122c6576002600083815260200190815260200160002080548091906001016121d79190612a97565b5060405180606001604052808281526020018483815181106121f557fe5b6020026020010151815260200185838151811061220e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060026000848152602001908152602001600020828154811061224d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506121a9565b5060008090505b83518110156123ea576003600083815260200190815260200160002080548091906001016122fb9190612a97565b50604051806060016040528082815260200184838151811061231957fe5b6020026020010151815260200185838151811061233257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060036000848152602001908152602001600020828154811061237157fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506122cd565b50505050565b60008082840190508381101561240557600080fd5b8091505092915050565b612417612b21565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061244882612830565b61245157600080fd5b600061245c8361287e565b905060608160405190808252806020026020018201604052801561249a57816020015b612487612b3b565b81526020019060019003908161247f5790505b50905060006124ac85602001516128ef565b8560200151019050600080600090505b8481101561250d576124cd83612978565b91506040518060400160405280838152602001848152508482815181106124f057fe5b6020026020010181905250818301925080806001019150506124bc565b5082945050505050919050565b600080826000015111801561253457506021826000015111155b61253d57600080fd5b600061254c83602001516128ef565b9050600081846000015103905060008083866020015101905080519150602083101561257f57826020036101000a820491505b81945050505050919050565b6000601582600001511461259e57600080fd5b6125a78261251a565b9050919050565b6060818301845110156125c057600080fd5b60608215600081146125dd5760405191506020820160405261262e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561261b57805183526020830192506020810190506125fe565b50868552601f19601f8301166040525050505b50809150509392505050565b6000806000806041855114612655576000935050505061273e565b602085015192506040850151915060ff6041860151169050601b8160ff16101561268057601b810190505b601b8160ff16141580156126985750601c8160ff1614155b156126a9576000935050505061273e565b6000600187838686604051600081526020016040526040516126ce9493929190613731565b6020604051602081039080840390855afa1580156126f0573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561273657600080fd5b809450505050505b92915050565b6060600082600001511161275757600080fd5b600061276683602001516128ef565b905060008184600001510390506060816040519080825280601f01601f1916602001820160405280156127a85781602001600182028038833980820191505090505b50905060008160200190506127c4848760200151018285612a30565b81945050505050919050565b6000808314156127e35760009050612804565b60008284029050828482816127f457fe5b04146127ff57600080fd5b809150505b92915050565b600080821161281857600080fd5b600082848161282357fe5b0490508091505092915050565b600080826000015114156128475760009050612879565b60008083602001519050805160001a915060c060ff168260ff16101561287257600092505050612879565b6001925050505b919050565b6000808260000151141561289557600090506128ea565b600080905060006128a984602001516128ef565b84602001510190506000846000015185602001510190505b808210156128e3576128d282612978565b8201915082806001019350506128c1565b8293505050505b919050565b600080825160001a9050608060ff1681101561290f576000915050612973565b60b860ff16811080612934575060c060ff168110158015612933575060f860ff1681105b5b15612943576001915050612973565b60c060ff168110156129635760018060b80360ff16820301915050612973565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156129995760019150612a26565b60b860ff168110156129b6576001608060ff168203019150612a25565b60c060ff168110156129e65760b78103600185019450806020036101000a85510460018201810193505050612a24565b60f860ff16811015612a0357600160c060ff168203019150612a23565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415612a3e57612a92565b5b602060ff168110612a6e5782518252602060ff1683019250602060ff1682019150602060ff1681039050612a3f565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b815481835581811115612ac457600302816003028360005260206000209182019101612ac39190612b55565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b612ba891905b80821115612ba45760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600301612b5b565b5090565b90565b600081359050612bba81613b33565b92915050565b600081359050612bcf81613b4a565b92915050565b600081519050612be481613b4a565b92915050565b60008083601f840112612bfc57600080fd5b8235905067ffffffffffffffff811115612c1557600080fd5b602083019150836001820283011115612c2d57600080fd5b9250929050565b600082601f830112612c4557600080fd5b8135612c58612c5382613982565b613955565b91508082526020830160208301858383011115612c7457600080fd5b612c7f838284613add565b50505092915050565b600081359050612c9781613b61565b92915050565b600060208284031215612caf57600080fd5b6000612cbd84828501612bab565b91505092915050565b600060208284031215612cd857600080fd5b6000612ce684828501612bc0565b91505092915050565b600060208284031215612d0157600080fd5b6000612d0f84828501612bd5565b91505092915050565b60008060408385031215612d2b57600080fd5b6000612d3985828601612bc0565b9250506020612d4a85828601612bc0565b9150509250929050565b600080600060608486031215612d6957600080fd5b6000612d7786828701612bc0565b9350506020612d8886828701612bc0565b925050604084013567ffffffffffffffff811115612da557600080fd5b612db186828701612c34565b9150509250925092565b60008060008060808587031215612dd157600080fd5b600085013567ffffffffffffffff811115612deb57600080fd5b612df787828801612c34565b945050602085013567ffffffffffffffff811115612e1457600080fd5b612e2087828801612c34565b935050604085013567ffffffffffffffff811115612e3d57600080fd5b612e4987828801612c34565b925050606085013567ffffffffffffffff811115612e6657600080fd5b612e7287828801612c34565b91505092959194509250565b600060208284031215612e9057600080fd5b6000612e9e84828501612c88565b91505092915050565b60008060408385031215612eba57600080fd5b6000612ec885828601612c88565b9250506020612ed985828601612bab565b9150509250929050565b600080600060608486031215612ef857600080fd5b6000612f0686828701612c88565b9350506020612f1786828701612bc0565b925050604084013567ffffffffffffffff811115612f3457600080fd5b612f4086828701612c34565b9150509250925092565b60008060408385031215612f5d57600080fd5b6000612f6b85828601612c88565b9250506020612f7c85828601612c88565b9150509250929050565b600080600080600080600060a0888a031215612fa157600080fd5b6000612faf8a828b01612c88565b9750506020612fc08a828b01612c88565b9650506040612fd18a828b01612c88565b955050606088013567ffffffffffffffff811115612fee57600080fd5b612ffa8a828b01612bea565b9450945050608088013567ffffffffffffffff81111561301957600080fd5b6130258a828b01612bea565b925092505092959891949750929550565b60006130428383613066565b60208301905092915050565b600061305a83836135bd565b60208301905092915050565b61306f81613a52565b82525050565b61307e81613a52565b82525050565b600061308f826139ce565b6130998185613a09565b93506130a4836139ae565b8060005b838110156130d55781516130bc8882613036565b97506130c7836139ef565b9250506001810190506130a8565b5085935050505092915050565b60006130ed826139d9565b6130f78185613a1a565b9350613102836139be565b8060005b8381101561313357815161311a888261304e565b9750613125836139fc565b925050600181019050613106565b5085935050505092915050565b61314981613a64565b82525050565b61316061315b82613a70565b613b1f565b82525050565b61316f81613a9c565b82525050565b61318661318182613a9c565b613b29565b82525050565b6000613197826139e4565b6131a18185613a2b565b93506131b1818560208601613aec565b80840191505092915050565b60006131ca600483613a47565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b600061320a602d83613a36565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000613270600f83613a47565b91507f6865696d64616c6c2d50357258776700000000000000000000000000000000006000830152600f82019050919050565b60006132b0601383613a36565b91507f436861696e20494420697320696e76616c6964000000000000000000000000006000830152602082019050919050565b60006132f0600f83613a36565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000613330601383613a36565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000613370604583613a36565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b60006133fc602a83613a36565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613462601483613a36565b91507f566f7465207479706520697320696e76616c69640000000000000000000000006000830152602082019050919050565b60006134a2601683613a36565b91507f5472616e73616374696f6e20697320696e76616c6964000000000000000000006000830152602082019050919050565b60006134e2600583613a47565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613522602483613a36565b91507f4e6f7420656e6f7567687420706f77657220746f206368616e6765207468652060008301527f7370616e000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60608201600082015161359160008501826135bd565b5060208201516135a460208501826135bd565b5060408201516135b76040850182613066565b50505050565b6135c681613ac6565b82525050565b6135d581613ac6565b82525050565b6135e481613ad0565b82525050565b60006135f6828561314f565b6001820191506136068284613175565b6020820191508190509392505050565b6000613622828661314f565b6001820191506136328285613175565b6020820191506136428284613175565b602082019150819050949350505050565b600061365f828461318c565b915081905092915050565b6000613675826131bd565b9150819050919050565b600061368a82613263565b9150819050919050565b600061369f826134d5565b9150819050919050565b60006020820190506136be6000830184613075565b92915050565b600060408201905081810360008301526136de8185613084565b905081810360208301526136f281846130e2565b90509392505050565b60006020820190506137106000830184613140565b92915050565b600060208201905061372b6000830184613166565b92915050565b60006080820190506137466000830187613166565b61375360208301866135db565b6137606040830185613166565b61376d6060830184613166565b95945050505050565b6000602082019050818103600083015261378f816131fd565b9050919050565b600060208201905081810360008301526137af816132a3565b9050919050565b600060208201905081810360008301526137cf816132e3565b9050919050565b600060208201905081810360008301526137ef81613323565b9050919050565b6000602082019050818103600083015261380f81613363565b9050919050565b6000602082019050818103600083015261382f816133ef565b9050919050565b6000602082019050818103600083015261384f81613455565b9050919050565b6000602082019050818103600083015261386f81613495565b9050919050565b6000602082019050818103600083015261388f81613515565b9050919050565b60006060820190506138ab600083018461357b565b92915050565b60006020820190506138c660008301846135cc565b92915050565b60006060820190506138e160008301866135cc565b6138ee60208301856135cc565b6138fb6040830184613075565b949350505050565b600060608201905061391860008301866135cc565b61392560208301856135cc565b61393260408301846135cc565b949350505050565b600060208201905061394f60008301846135db565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561397857600080fd5b8060405250919050565b600067ffffffffffffffff82111561399957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000613a5d82613aa6565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b83811015613b0a578082015181840152602081019050613aef565b83811115613b19576000848401525b50505050565b6000819050919050565b6000819050919050565b613b3c81613a52565b8114613b4757600080fd5b50565b613b5381613a9c565b8114613b5e57600080fd5b50565b613b6a81613ac6565b8114613b7557600080fd5b5056fea365627a7a7231582041043c020490417f03b23833da19152e2e105982aaa0228db2459085c981a3f16c6578706572696d656e74616cf564736f6c63430005100040" + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a919081019061290d565b610706565b60405161021e939291906131ec565b60405180910390f35b610241600480360361023c919081019061290d565b61075d565b60405161024f92919061302d565b60405180910390f35b610272600480360361026d9190810190612936565b610939565b60405161027f9190613064565b60405180910390f35b6102a2600480360361029d9190810190612a15565b610a91565b005b6102be60048036036102b99190810190612936565b6110f4565b6040516102cb9190613064565b60405180910390f35b6102dc61124b565b6040516102e9919061319a565b60405180910390f35b61030c6004803603610307919081019061286a565b611250565b604051610319919061307f565b60405180910390f35b61033c6004803603610337919081019061290d565b6112d1565b604051610349919061319a565b60405180910390f35b61035a611401565b6040516103679190613012565b60405180910390f35b61038a600480360361038591908101906128a6565b611419565b6040516103979190613064565b60405180910390f35b6103a86114e4565b6040516103b5919061307f565b60405180910390f35b6103d860048036036103d39190810190612972565b6114fb565b6040516103e5919061319a565b60405180910390f35b61040860048036036104039190810190612936565b6115e3565b604051610415919061317f565b60405180910390f35b61042661174b565b604051610433919061319a565b60405180910390f35b610456600480360361045191908101906127ef565b61175b565b6040516104639190613064565b60405180910390f35b61048660048036036104819190810190612818565b611775565b604051610493919061307f565b60405180910390f35b6104a46117f3565b6040516104b3939291906131ec565b60405180910390f35b6104c4611867565b6040516104d292919061302d565b60405180910390f35b6104e3611957565b6040516104f0919061319a565b60405180910390f35b610513600480360361050e91908101906129d9565b61195c565b604051610522939291906131b5565b60405180910390f35b610545600480360361054091908101906127ef565b6119c0565b6040516105529190613064565b60405180910390f35b6105636119da565b604051610570919061307f565b60405180910390f35b610593600480360361058e919081019061290d565b6119f1565b6040516105a0919061319a565b60405180910390f35b6105b1611b22565b6040516105be919061307f565b60405180910390f35b6105cf611b39565b6040516105de939291906131ec565b60405180910390f35b61060160048036036105fc919081019061290d565b611b9a565b60405161060e919061319a565b60405180910390f35b61061f611c9a565b60405161062d92919061302d565b60405180910390f35b610650600480360361064b919081019061290d565b611cae565b60405161065d919061319a565b60405180910390f35b61066e611ccf565b60405161067b9190613223565b60405180910390f35b61069e600480360361069991908101906129d9565b611cd4565b6040516106ad939291906131b5565b60405180910390f35b6106be611d38565b6040516106cb919061319a565b60405180910390f35b6106ee60048036036106e9919081019061290d565b611d4a565b6040516106fd939291906131ec565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b6060806007831161077957610770611867565b91509150610934565b600061078484611b9a565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610add57600080fd5b6000610ae761174b565b90506000811415610afb57610afa611d74565b5b610b0f60018261209590919063ffffffff16565b8814610b50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b47906130ff565b60405180910390fd5b868611610b92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b899061315f565b60405180910390fd5b6000600460018989030181610ba357fe5b0614610be4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bdb9061313f565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c34906130df565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610c96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8d9061311f565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d3091906125e9565b506000600160008a815260200190815260200160002081610d5191906125e9565b506060610da9610da487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120b4565b6120e2565b905060008090505b8151811015610f1b576060610dd8838381518110610dcb57fe5b60200260200101516120e2565b90506000808c81526020019081526020016000208054809190600101610dfe91906125e9565b506040518060600160405280610e2783600081518110610e1a57fe5b60200260200101516121bf565b8152602001610e4983600181518110610e3c57fe5b60200260200101516121bf565b8152602001610e6b83600281518110610e5e57fe5b6020026020010151612230565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ea157fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610db1565b506060610f73610f6e86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120b4565b6120e2565b905060008090505b81518110156110e7576060610fa2838381518110610f9557fe5b60200260200101516120e2565b9050600160008d81526020019081526020016000208054809190600101610fc991906125e9565b506040518060600160405280610ff283600081518110610fe557fe5b60200260200101516121bf565b81526020016110148360018151811061100757fe5b60200260200101516121bf565b81526020016110368360028151811061102957fe5b6020026020010151612230565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e8152602001908152602001600020838154811061106d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610f7b565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111c6578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061112a565b50505050905060008090505b815181101561123e578373ffffffffffffffffffffffffffffffffffffffff168282815181106111fe57fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561123157600192505050611245565b80806001019150506111d2565b5060009150505b92915050565b600481565b60006002600160f81b848460405160200161126d93929190612f7f565b6040516020818303038152906040526040516112899190612fbc565b602060405180830381855afa1580156112a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112c99190810190612841565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113a3578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611307565b505050509050600080905060008090505b82518110156113f6576113e78382815181106113cc57fe5b6020026020010151602001518361209590919063ffffffff16565b915080806001019150506113b4565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161143057fe5b0402905060008111156114495761144687611775565b91505b6000602190505b8181116114d35760006001820388015190508188015195508060006020811061147557fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114ba576114b38685611250565b93506114c7565b6114c48487611250565b93505b50602181019050611450565b508782149450505050509392505050565b6040516114f090612fe8565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff1610156115d6576060611538868367ffffffffffffffff166041612253565b9050600061154f82896122df90919063ffffffff16565b905061155961261b565b6115638a836115e3565b905061156f8a836110f4565b80156115a657508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115c8578194506115c581602001518761209590919063ffffffff16565b95505b50505060418101905061150d565b5081925050509392505050565b6115eb61261b565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116bb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061161f565b50505050905060008090505b8151811015611743578373ffffffffffffffffffffffffffffffffffffffff168282815181106116f357fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156117365781818151811061172757fe5b60200260200101519250611743565b80806001019150506116c7565b505092915050565b600061175643611b9a565b905090565b600061176e61176861174b565b836110f4565b9050919050565b60006002600060f81b83604051602001611790929190612f53565b6040516020818303038152906040526040516117ac9190612fbc565b602060405180830381855afa1580156117c9573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506117ec9190810190612841565b9050919050565b600080600080611814600161180661174b565b61209590919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b6060806060600160405190808252806020026020018201604052801561189c5781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f7816000815181106118c157fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506060600160405190808252806020026020018201604052801561192d5781602001602082028038833980820191505090505b509050600a8160008151811061193f57fe5b60200260200101818152505081819350935050509091565b600781565b6001602052816000526040600020818154811061197557fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006119d36119cd61174b565b83610939565b9050919050565b6040516119e690612fd3565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611ac4578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611a28565b505050509050600080905060008090505b8251811015611b1757611b08838281518110611aed57fe5b6020026020010151602001518361209590919063ffffffff16565b91508080600101915050611ad5565b508092505050919050565b604051611b2e90612ffd565b604051809103902081565b600080600080611b4761174b565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611c5a57611bb7612652565b6002600060036001850381548110611bcb57fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611c2857506000816040015114155b8015611c38575080604001518411155b15611c4b57806000015192505050611c95565b50808060019003915050611ba6565b5060006003805490501115611c9057600360016003805490500381548110611c7e57fe5b90600052602060002001549050611c95565b600090505b919050565b606080611ca64361075d565b915091509091565b60038181548110611cbb57fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611ced57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060044381611d4457fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611d7f611867565b809250819350505060008090506040518060600160405280828152602001600081526020016007815250600260008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506003819080600181540180825580915050906001820390600052602060002001600090919290919091505550600080600083815260200190815260200160002081611e2891906125e9565b5060006001600083815260200190815260200160002081611e4991906125e9565b5060008090505b8351811015611f6b576000808381526020019081526020016000208054809190600101611e7d91906125e9565b506040518060600160405280828152602001848381518110611e9b57fe5b60200260200101518152602001858381518110611eb457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506000808481526020019081526020016000208281548110611ef257fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611e50565b5060008090505b835181101561208f57600160008381526020019081526020016000208054809190600101611fa091906125e9565b506040518060600160405280828152602001848381518110611fbe57fe5b60200260200101518152602001858381518110611fd757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061201657fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611f72565b50505050565b6000808284019050838110156120aa57600080fd5b8091505092915050565b6120bc612673565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606120ed826123e9565b6120f657600080fd5b600061210183612437565b905060608160405190808252806020026020018201604052801561213f57816020015b61212c61268d565b8152602001906001900390816121245790505b509050600061215185602001516124a8565b8560200151019050600080600090505b848110156121b25761217283612531565b915060405180604001604052808381526020018481525084828151811061219557fe5b602002602001018190525081830192508080600101915050612161565b5082945050505050919050565b60008082600001511180156121d957506021826000015111155b6121e257600080fd5b60006121f183602001516124a8565b9050600081846000015103905060008083866020015101905080519150602083101561222457826020036101000a820491505b81945050505050919050565b6000601582600001511461224357600080fd5b61224c826121bf565b9050919050565b60608183018451101561226557600080fd5b6060821560008114612282576040519150602082016040526122d3565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156122c057805183526020830192506020810190506122a3565b50868552601f19601f8301166040525050505b50809150509392505050565b60008060008060418551146122fa57600093505050506123e3565b602085015192506040850151915060ff6041860151169050601b8160ff16101561232557601b810190505b601b8160ff161415801561233d5750601c8160ff1614155b1561234e57600093505050506123e3565b600060018783868660405160008152602001604052604051612373949392919061309a565b6020604051602081039080840390855afa158015612395573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156123db57600080fd5b809450505050505b92915050565b600080826000015114156124005760009050612432565b60008083602001519050805160001a915060c060ff168260ff16101561242b57600092505050612432565b6001925050505b919050565b6000808260000151141561244e57600090506124a3565b6000809050600061246284602001516124a8565b84602001510190506000846000015185602001510190505b8082101561249c5761248b82612531565b82019150828060010193505061247a565b8293505050505b919050565b600080825160001a9050608060ff168110156124c857600091505061252c565b60b860ff168110806124ed575060c060ff1681101580156124ec575060f860ff1681105b5b156124fc57600191505061252c565b60c060ff1681101561251c5760018060b80360ff1682030191505061252c565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561255257600191506125df565b60b860ff1681101561256f576001608060ff1682030191506125de565b60c060ff1681101561259f5760b78103600185019450806020036101000a855104600182018101935050506125dd565b60f860ff168110156125bc57600160c060ff1682030191506125dc565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b8154818355818111156126165760030281600302836000526020600020918201910161261591906126a7565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b6126fa91905b808211156126f65760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016126ad565b5090565b90565b60008135905061270c8161341c565b92915050565b60008135905061272181613433565b92915050565b60008151905061273681613433565b92915050565b60008083601f84011261274e57600080fd5b8235905067ffffffffffffffff81111561276757600080fd5b60208301915083600182028301111561277f57600080fd5b9250929050565b600082601f83011261279757600080fd5b81356127aa6127a58261326b565b61323e565b915080825260208301602083018583830111156127c657600080fd5b6127d18382846133c6565b50505092915050565b6000813590506127e98161344a565b92915050565b60006020828403121561280157600080fd5b600061280f848285016126fd565b91505092915050565b60006020828403121561282a57600080fd5b600061283884828501612712565b91505092915050565b60006020828403121561285357600080fd5b600061286184828501612727565b91505092915050565b6000806040838503121561287d57600080fd5b600061288b85828601612712565b925050602061289c85828601612712565b9150509250929050565b6000806000606084860312156128bb57600080fd5b60006128c986828701612712565b93505060206128da86828701612712565b925050604084013567ffffffffffffffff8111156128f757600080fd5b61290386828701612786565b9150509250925092565b60006020828403121561291f57600080fd5b600061292d848285016127da565b91505092915050565b6000806040838503121561294957600080fd5b6000612957858286016127da565b9250506020612968858286016126fd565b9150509250929050565b60008060006060848603121561298757600080fd5b6000612995868287016127da565b93505060206129a686828701612712565b925050604084013567ffffffffffffffff8111156129c357600080fd5b6129cf86828701612786565b9150509250925092565b600080604083850312156129ec57600080fd5b60006129fa858286016127da565b9250506020612a0b858286016127da565b9150509250929050565b600080600080600080600060a0888a031215612a3057600080fd5b6000612a3e8a828b016127da565b9750506020612a4f8a828b016127da565b9650506040612a608a828b016127da565b955050606088013567ffffffffffffffff811115612a7d57600080fd5b612a898a828b0161273c565b9450945050608088013567ffffffffffffffff811115612aa857600080fd5b612ab48a828b0161273c565b925092505092959891949750929550565b6000612ad18383612af5565b60208301905092915050565b6000612ae98383612f26565b60208301905092915050565b612afe8161333b565b82525050565b612b0d8161333b565b82525050565b6000612b1e826132b7565b612b2881856132f2565b9350612b3383613297565b8060005b83811015612b64578151612b4b8882612ac5565b9750612b56836132d8565b925050600181019050612b37565b5085935050505092915050565b6000612b7c826132c2565b612b868185613303565b9350612b91836132a7565b8060005b83811015612bc2578151612ba98882612add565b9750612bb4836132e5565b925050600181019050612b95565b5085935050505092915050565b612bd88161334d565b82525050565b612bef612bea82613359565b613408565b82525050565b612bfe81613385565b82525050565b612c15612c1082613385565b613412565b82525050565b6000612c26826132cd565b612c308185613314565b9350612c408185602086016133d5565b80840191505092915050565b6000612c59600483613330565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612c99602d8361331f565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612cff600f8361331f565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612d3f60138361331f565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612d7f60458361331f565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000612e0b602a8361331f565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000612e71600e83613330565b91507f6865696d64616c6c2d31353030310000000000000000000000000000000000006000830152600e82019050919050565b6000612eb1600583613330565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b606082016000820151612efa6000850182612f26565b506020820151612f0d6020850182612f26565b506040820151612f206040850182612af5565b50505050565b612f2f816133af565b82525050565b612f3e816133af565b82525050565b612f4d816133b9565b82525050565b6000612f5f8285612bde565b600182019150612f6f8284612c04565b6020820191508190509392505050565b6000612f8b8286612bde565b600182019150612f9b8285612c04565b602082019150612fab8284612c04565b602082019150819050949350505050565b6000612fc88284612c1b565b915081905092915050565b6000612fde82612c4c565b9150819050919050565b6000612ff382612e64565b9150819050919050565b600061300882612ea4565b9150819050919050565b60006020820190506130276000830184612b04565b92915050565b600060408201905081810360008301526130478185612b13565b9050818103602083015261305b8184612b71565b90509392505050565b60006020820190506130796000830184612bcf565b92915050565b60006020820190506130946000830184612bf5565b92915050565b60006080820190506130af6000830187612bf5565b6130bc6020830186612f44565b6130c96040830185612bf5565b6130d66060830184612bf5565b95945050505050565b600060208201905081810360008301526130f881612c8c565b9050919050565b6000602082019050818103600083015261311881612cf2565b9050919050565b6000602082019050818103600083015261313881612d32565b9050919050565b6000602082019050818103600083015261315881612d72565b9050919050565b6000602082019050818103600083015261317881612dfe565b9050919050565b60006060820190506131946000830184612ee4565b92915050565b60006020820190506131af6000830184612f35565b92915050565b60006060820190506131ca6000830186612f35565b6131d76020830185612f35565b6131e46040830184612b04565b949350505050565b60006060820190506132016000830186612f35565b61320e6020830185612f35565b61321b6040830184612f35565b949350505050565b60006020820190506132386000830184612f44565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561326157600080fd5b8060405250919050565b600067ffffffffffffffff82111561328257600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006133468261338f565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156133f35780820151818401526020810190506133d8565b83811115613402576000848401525b50505050565b6000819050919050565b6000819050919050565b6134258161333b565b811461343057600080fd5b50565b61343c81613385565b811461344757600080fd5b50565b613453816133af565b811461345e57600080fd5b5056fea365627a7a723158208af21d8e799fd1406e4b7808af903d8055606c3aa8d3ec80d8e21f0514e9bf676c6578706572696d656e74616cf564736f6c634300050c0040" }, "0000000000000000000000000000000000001001": { "balance": "0x0", - "code": "0x" + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e9610411565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610429565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461019757600080fd5b60606101ee6101e985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061042f565b61045d565b9050600061020f8260008151811061020257fe5b602002602001015161053a565b9050806001600054011461028b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006102bb836001815181106102ae57fe5b60200260200101516105ab565b905060606102dc846002815181106102cf57fe5b60200260200101516105ce565b90506102e78261065a565b15610406576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610341578082015181840152602081019050610326565b50505050905090810190601f16801561036e5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104376108da565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061046882610673565b61047157600080fd5b600061047c836106c1565b90506060816040519080825280602002602001820160405280156104ba57816020015b6104a76108f4565b81526020019060019003908161049f5790505b50905060006104cc8560200151610732565b8560200151019050600080600090505b8481101561052d576104ed836107bb565b915060405180604001604052808381526020018481525084828151811061051057fe5b6020026020010181905250818301925080806001019150506104dc565b5082945050505050919050565b600080826000015111801561055457506021826000015111155b61055d57600080fd5b600061056c8360200151610732565b9050600081846000015103905060008083866020015101905080519150602083101561059f57826020036101000a820491505b81945050505050919050565b600060158260000151146105be57600080fd5b6105c78261053a565b9050919050565b606060008260000151116105e157600080fd5b60006105f08360200151610732565b905060008184600001510390506060816040519080825280601f01601f1916602001820160405280156106325781602001600182028038833980820191505090505b509050600081602001905061064e848760200151018285610873565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b6000808260000151141561068a57600090506106bc565b60008083602001519050805160001a915060c060ff168260ff1610156106b5576000925050506106bc565b6001925050505b919050565b600080826000015114156106d8576000905061072d565b600080905060006106ec8460200151610732565b84602001510190506000846000015185602001510190505b8082101561072657610715826107bb565b820191508280600101935050610704565b8293505050505b919050565b600080825160001a9050608060ff168110156107525760009150506107b6565b60b860ff16811080610777575060c060ff168110158015610776575060f860ff1681105b5b156107865760019150506107b6565b60c060ff168110156107a65760018060b80360ff168203019150506107b6565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156107dc5760019150610869565b60b860ff168110156107f9576001608060ff168203019150610868565b60c060ff168110156108295760b78103600185019450806020036101000a85510460018201810193505050610867565b60f860ff1681101561084657600160c060ff168203019150610866565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415610881576108d5565b5b602060ff1681106108b15782518252602060ff1683019250602060ff1682019150602060ff1681039050610882565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a723158206e562292874be6a994dcfabfea65957791c1491194eeb7dea6f7eaf1390c036e64736f6c634300050c0032" }, "0000000000000000000000000000000000001010": { "balance": "0x204fce28085b549b31600000", - "code": "0x" + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e626023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e3f6023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f3a9900000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611ed7605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b613a9981565b60015481565b604051806080016040528060528152602001611e85605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed7605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd3573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820539379fc818a23e69edb3d3a2323efa049847b7691be5bd708c0770ce4be296964736f6c634300050c0032" }, "71562b71999873DB5b286dF957af199Ec94617F7": { "balance": "0x3635c9adc5dea00000" diff --git a/consensus/bor/bor_test/helper.go b/consensus/bor/bor_test/helper.go index 54ab949983a9861a096f4182bca649563ac1790a..d02c3463fc4e942ebab69c34c9f2952e62b55c4e 100644 --- a/consensus/bor/bor_test/helper.go +++ b/consensus/bor/bor_test/helper.go @@ -5,24 +5,38 @@ import ( "encoding/json" "io/ioutil" "math/big" + "sort" "testing" + "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus/bor" "github.com/maticnetwork/bor/core" - "github.com/maticnetwork/bor/core/state" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/crypto/secp256k1" "github.com/maticnetwork/bor/eth" "github.com/maticnetwork/bor/ethdb" "github.com/maticnetwork/bor/node" + "github.com/maticnetwork/bor/params" ) var ( + // The genesis for tests was generated with following parameters extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal - privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7 + + // Only this account is a validator for the 0th span + privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + key, _ = crypto.HexToECDSA(privKey) + addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7 + + // This account is one the validators for 1st span (0-indexed) + privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3" + key2, _ = crypto.HexToECDSA(privKey2) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791 + + validatorHeaderBytesLength = common.AddressLength + 20 // address + power + sprintSize uint64 = 4 + spanSize uint64 = 8 ) type initializeData struct { @@ -81,37 +95,77 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { } } -func insertNewBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, header *types.Header, statedb *state.StateDB, privKey []byte) { - _, err := _bor.FinalizeAndAssemble(chain, header, statedb, nil, nil, nil) - if err != nil { +func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) { + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { t.Fatalf("%s", err) } +} + +func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block { + header := block.Header() + header.Number.Add(header.Number, big.NewInt(1)) + number := header.Number.Uint64() - sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), privKey) + if signer == nil { + signer = getSignerKey(header.Number.Uint64()) + } + + header.ParentHash = block.Hash() + header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig) + header.Extra = make([]byte, 32+65) // vanity + extraSeal + + currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)} + + isSpanEnd := (number+1)%spanSize == 0 + isSpanStart := number%spanSize == 0 + isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0 + if isSpanEnd { + _, heimdallSpan := loadSpanFromFile(t) + // this is to stash the validator bytes in the header + currentValidators = heimdallSpan.ValidatorSet.Validators + } else if isSpanStart { + header.Difficulty = new(big.Int).SetInt64(3) + } + if isSprintEnd { + sort.Sort(bor.ValidatorsByAddress(currentValidators)) + validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength) + header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal + for i, val := range currentValidators { + copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes()) + } + copy(header.Extra[32:], validatorBytes) + } + + state, err := chain.State() if err != nil { t.Fatalf("%s", err) } - copy(header.Extra[len(header.Extra)-extraSeal:], sig) - - block := types.NewBlockWithHeader(header) - if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + _, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil) + if err != nil { t.Fatalf("%s", err) } + sign(t, header, signer) + return types.NewBlockWithHeader(header) } -func buildMinimalNextHeader(t *testing.T, block *types.Block, period uint64) *types.Header { - header := block.Header() - header.Number.Add(header.Number, big.NewInt(1)) - header.ParentHash = block.Hash() - header.Time += (period + 1) - header.Extra = make([]byte, 97) // vanity (32) + extraSeal (65) - _key, _ := hex.DecodeString(privKey) - sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), _key) +func sign(t *testing.T, header *types.Header, signer []byte) { + sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), signer) if err != nil { t.Fatalf("%s", err) } copy(header.Extra[len(header.Extra)-extraSeal:], sig) - return header +} + +func stateSyncEventsPayload(t *testing.T) *bor.ResponseWithHeight { + stateData, err := ioutil.ReadFile("states.json") + if err != nil { + t.Fatalf("%s", err) + } + res := &bor.ResponseWithHeight{} + if err := json.Unmarshal(stateData, res); err != nil { + t.Fatalf("%s", err) + } + return res } func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) { @@ -130,3 +184,14 @@ func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) } return res, heimdallSpan } + +func getSignerKey(number uint64) []byte { + signerKey := privKey + isSpanStart := number%spanSize == 0 + if isSpanStart { + // validator set in the new span has changed + signerKey = privKey2 + } + _key, _ := hex.DecodeString(signerKey) + return _key +} diff --git a/consensus/bor/bor_test/snapshot_test.go b/consensus/bor/bor_test/snapshot_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6eb43b3e60374dc594cdbd02209e8a73de81607e --- /dev/null +++ b/consensus/bor/bor_test/snapshot_test.go @@ -0,0 +1,125 @@ +package bortest + +import ( + "math/rand" + "sort" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/consensus/bor" +) + +const ( + numVals = 100 +) + +func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) { + validators := buildRandomValidatorSet(numVals) + validatorSet := bor.NewValidatorSet(validators) + snap := bor.Snapshot{ + ValidatorSet: validatorSet, + } + + // proposer is signer + signer := validatorSet.Proposer.Address + successionNumber, err := snap.GetSignerSuccessionNumber(signer) + if err != nil { + t.Fatalf("%s", err) + } + assert.Equal(t, 0, successionNumber) +} + +func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { + validators := buildRandomValidatorSet(numVals) + + // sort validators by address, which is what bor.NewValidatorSet also does + sort.Sort(bor.ValidatorsByAddress(validators)) + proposerIndex := 32 + signerIndex := 56 + // give highest ProposerPriority to a particular val, so that they become the proposer + validators[proposerIndex].VotingPower = 200 + snap := bor.Snapshot{ + ValidatorSet: bor.NewValidatorSet(validators), + } + + // choose a signer at an index greater than proposer index + signer := snap.ValidatorSet.Validators[signerIndex].Address + successionNumber, err := snap.GetSignerSuccessionNumber(signer) + if err != nil { + t.Fatalf("%s", err) + } + assert.Equal(t, signerIndex-proposerIndex, successionNumber) +} + +func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { + validators := buildRandomValidatorSet(numVals) + proposerIndex := 98 + signerIndex := 11 + // give highest ProposerPriority to a particular val, so that they become the proposer + validators[proposerIndex].VotingPower = 200 + snap := bor.Snapshot{ + ValidatorSet: bor.NewValidatorSet(validators), + } + + // choose a signer at an index greater than proposer index + signer := snap.ValidatorSet.Validators[signerIndex].Address + successionNumber, err := snap.GetSignerSuccessionNumber(signer) + if err != nil { + t.Fatalf("%s", err) + } + assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber) +} + +func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { + validators := buildRandomValidatorSet(numVals) + snap := bor.Snapshot{ + ValidatorSet: bor.NewValidatorSet(validators), + } + dummyProposerAddress := randomAddress() + snap.ValidatorSet.Proposer = &bor.Validator{Address: dummyProposerAddress} + // choose any signer + signer := snap.ValidatorSet.Validators[3].Address + _, err := snap.GetSignerSuccessionNumber(signer) + assert.NotNil(t, err) + e, ok := err.(*bor.UnauthorizedProposerError) + assert.True(t, ok) + assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer) +} + +func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { + validators := buildRandomValidatorSet(numVals) + snap := bor.Snapshot{ + ValidatorSet: bor.NewValidatorSet(validators), + } + dummySignerAddress := randomAddress() + _, err := snap.GetSignerSuccessionNumber(dummySignerAddress) + assert.NotNil(t, err) + e, ok := err.(*bor.UnauthorizedSignerError) + assert.True(t, ok) + assert.Equal(t, dummySignerAddress.Bytes(), e.Signer) +} + +func buildRandomValidatorSet(numVals int) []*bor.Validator { + rand.Seed(time.Now().Unix()) + validators := make([]*bor.Validator, numVals) + for i := 0; i < numVals; i++ { + validators[i] = &bor.Validator{ + Address: randomAddress(), + // cannot process validators with voting power 0, hence +1 + VotingPower: int64(rand.Intn(99) + 1), + } + } + + // sort validators by address, which is what bor.NewValidatorSet also does + sort.Sort(bor.ValidatorsByAddress(validators)) + return validators +} + +func randomAddress() common.Address { + bytes := make([]byte, 32) + rand.Read(bytes) + return common.BytesToAddress(bytes) +} diff --git a/consensus/bor/bor_test/span.json b/consensus/bor/bor_test/span.json index f4be94eeb8bb27061bff15ea983dd4754919268c..893d3db4a6e9b39e707bf0b143dd88a108767815 100644 --- a/consensus/bor/bor_test/span.json +++ b/consensus/bor/bor_test/span.json @@ -6,85 +6,57 @@ "end_block": 6655, "validator_set": { "validators": [{ - "ID": 3, - "startEpoch": 0, - "endEpoch": 0, - "power": 10000, - "pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1", - "signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c", - "last_updated": 0, - "accum": -40000 - }, { - "ID": 4, - "startEpoch": 0, - "endEpoch": 0, - "power": 10000, - "pubKey": "0x04d9d09f2afc9da3cccc164e8112eb6911a63f5ede10169768f800df83cf99c73f944411e9d4fac3543b11c5f84a82e56b36cfcd34f1d065855c1e2b27af8b5247", - "signer": "0x461295d3d9249215e758e939a150ab180950720b", - "last_updated": 0, - "accum": 10000 - }, { "ID": 5, "startEpoch": 0, "endEpoch": 0, - "power": 10000, + "power": 30, "pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932", - "signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0", + "signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791", "last_updated": 0, "accum": 10000 }, { "ID": 1, "startEpoch": 0, "endEpoch": 0, - "power": 10000, + "power": 20, "pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead", - "signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3", + "signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a", "last_updated": 0, "accum": 10000 }, { "ID": 2, "startEpoch": 0, "endEpoch": 0, - "power": 10000, + "power": 10, "pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232", - "signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220", - "last_updated": 0, - "accum": 10000 - }], - "proposer": { - "ID": 3, - "startEpoch": 0, - "endEpoch": 0, - "power": 10000, - "pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1", - "signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220", + "signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c", "last_updated": 0, - "accum": -40000 - } + "accum": 5000 + }] }, "selected_producers": [{ "ID": 5, "startEpoch": 0, "endEpoch": 0, - "power": 1, + "power": 30, "pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932", - "signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0", + "signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791", "last_updated": 0, "accum": 10000 }, { "ID": 1, "startEpoch": 0, "endEpoch": 0, - "power": 1, + "power": 20, "pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead", - "signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3", + "signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a", "last_updated": 0, "accum": 10000 }, { "ID": 2, "startEpoch": 0, "endEpoch": 0, - "power": 2, + "power": 10, "pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232", "signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c", "last_updated": 0, diff --git a/consensus/bor/bor_test/states.json b/consensus/bor/bor_test/states.json new file mode 100644 index 0000000000000000000000000000000000000000..809998ad906d831de1a79793abcfabc506557998 --- /dev/null +++ b/consensus/bor/bor_test/states.json @@ -0,0 +1,23 @@ +{ + "height": "0", + "result": [ + { + "id": 1, + "contract": "0xb55969a6d60413a63291a1de572269875df541e3", + "data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014", + "tx_hash": "0x7b113e09d98b6d4be1dedfbc0746e34876de767f2cb8b58ff00160a160811dd6", + "log_index": 0, + "bor_chain_id": "15001", + "record_time": "2020-05-15T13:36:38.580995Z" + }, + { + "id": 2, + "contract": "0xb55969a6d60413a63291a1de572269875df541e3", + "data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000015", + "tx_hash": "0xb72358aff8e4d61f4de97a37a40ddda986c081e0de8036e0a78c4b61b067cba9", + "log_index": 0, + "bor_chain_id": "15001", + "record_time": "2020-05-15T13:42:37.319058Z" + } + ] +} diff --git a/consensus/bor/clerk.go b/consensus/bor/clerk.go index adcbfb78b46df3a0d9fec7abb3c4cce7b87e6389..1c78b5fdd454fa8c7a7d3af353fcee73ce930a26 100644 --- a/consensus/bor/clerk.go +++ b/consensus/bor/clerk.go @@ -1,6 +1,9 @@ package bor import ( + "fmt" + "time" + "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/common/hexutil" ) @@ -14,3 +17,33 @@ type EventRecord struct { LogIndex uint64 `json:"log_index" yaml:"log_index"` ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"` } + +type EventRecordWithTime struct { + EventRecord + Time time.Time `json:"record_time" yaml:"record_time"` +} + +// String returns the string representatin of span +func (e *EventRecordWithTime) String() string { + return fmt.Sprintf( + "id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s", + e.ID, + e.Contract.String(), + e.Data.String(), + e.TxHash.Hex(), + e.LogIndex, + e.ChainID, + e.Time.Format(time.RFC3339), + ) +} + +func (e *EventRecordWithTime) BuildEventRecord() *EventRecord { + return &EventRecord{ + ID: e.ID, + Contract: e.Contract, + Data: e.Data, + TxHash: e.TxHash, + LogIndex: e.LogIndex, + ChainID: e.ChainID, + } +} diff --git a/consensus/bor/errors.go b/consensus/bor/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..a1e60d1e219e50241996df3199dd720d43abbac8 --- /dev/null +++ b/consensus/bor/errors.go @@ -0,0 +1,143 @@ +package bor + +import ( + "fmt" + "time" +) + +// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded +type TotalVotingPowerExceededError struct { + Sum int64 + Validators []*Validator +} + +func (e *TotalVotingPowerExceededError) Error() string { + return fmt.Sprintf( + "Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v", + MaxTotalVotingPower, + e.Sum, + e.Validators, + ) +} + +type InvalidStartEndBlockError struct { + Start uint64 + End uint64 + CurrentHeader uint64 +} + +func (e *InvalidStartEndBlockError) Error() string { + return fmt.Sprintf( + "Invalid parameters start: %d and end block: %d params", + e.Start, + e.End, + ) +} + +type MaxCheckpointLengthExceededError struct { + Start uint64 + End uint64 +} + +func (e *MaxCheckpointLengthExceededError) Error() string { + return fmt.Sprintf( + "Start: %d and end block: %d exceed max allowed checkpoint length: %d", + e.Start, + e.End, + MaxCheckpointLength, + ) +} + +// MismatchingValidatorsError is returned if a last block in sprint contains a +// list of validators different from the one that local node calculated +type MismatchingValidatorsError struct { + Number uint64 + ValidatorSetSnap []byte + ValidatorSetHeader []byte +} + +func (e *MismatchingValidatorsError) Error() string { + return fmt.Sprintf( + "Mismatching validators at block %d\nValidatorBytes from snapshot: 0x%x\nValidatorBytes in Header: 0x%x\n", + e.Number, + e.ValidatorSetSnap, + e.ValidatorSetHeader, + ) +} + +type BlockTooSoonError struct { + Number uint64 + Succession int +} + +func (e *BlockTooSoonError) Error() string { + return fmt.Sprintf( + "Block %d was created too soon. Signer turn-ness number is %d\n", + e.Number, + e.Succession, + ) +} + +// UnauthorizedProposerError is returned if a header is [being] signed by an unauthorized entity. +type UnauthorizedProposerError struct { + Number uint64 + Proposer []byte +} + +func (e *UnauthorizedProposerError) Error() string { + return fmt.Sprintf( + "Proposer 0x%x is not a part of the producer set at block %d", + e.Proposer, + e.Number, + ) +} + +// UnauthorizedSignerError is returned if a header is [being] signed by an unauthorized entity. +type UnauthorizedSignerError struct { + Number uint64 + Signer []byte +} + +func (e *UnauthorizedSignerError) Error() string { + return fmt.Sprintf( + "Signer 0x%x is not a part of the producer set at block %d", + e.Signer, + e.Number, + ) +} + +// WrongDifficultyError is returned if the difficulty of a block doesn't match the +// turn of the signer. +type WrongDifficultyError struct { + Number uint64 + Expected uint64 + Actual uint64 + Signer []byte +} + +func (e *WrongDifficultyError) Error() string { + return fmt.Sprintf( + "Wrong difficulty at block %d, expected: %d, actual %d. Signer was %x\n", + e.Number, + e.Expected, + e.Actual, + e.Signer, + ) +} + +type InvalidStateReceivedError struct { + Number uint64 + LastStateID uint64 + To *time.Time + Event *EventRecordWithTime +} + +func (e *InvalidStateReceivedError) Error() string { + return fmt.Sprintf( + "Received invalid event %s at block %d. Requested events until %s. Last state id was %d", + e.Event, + e.Number, + e.To.Format(time.RFC3339), + e.LastStateID, + ) +} diff --git a/consensus/bor/genesis_contracts_client.go b/consensus/bor/genesis_contracts_client.go new file mode 100644 index 0000000000000000000000000000000000000000..17323f278d973ebb6561d4063b8d6d781d3cc79a --- /dev/null +++ b/consensus/bor/genesis_contracts_client.go @@ -0,0 +1,102 @@ +package bor + +import ( + "context" + "math" + "math/big" + "strings" + + "github.com/maticnetwork/bor/accounts/abi" + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/common/hexutil" + "github.com/maticnetwork/bor/core/state" + "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/internal/ethapi" + "github.com/maticnetwork/bor/log" + "github.com/maticnetwork/bor/params" + "github.com/maticnetwork/bor/rlp" + "github.com/maticnetwork/bor/rpc" +) + +type GenesisContractsClient struct { + validatorSetABI abi.ABI + stateReceiverABI abi.ABI + ValidatorContract string + StateReceiverContract string + chainConfig *params.ChainConfig + ethAPI *ethapi.PublicBlockChainAPI +} + +const validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]` +const stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` + +func NewGenesisContractsClient( + chainConfig *params.ChainConfig, + validatorContract, + stateReceiverContract string, + ethAPI *ethapi.PublicBlockChainAPI, +) *GenesisContractsClient { + vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) + sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) + return &GenesisContractsClient{ + validatorSetABI: vABI, + stateReceiverABI: sABI, + ValidatorContract: validatorContract, + StateReceiverContract: stateReceiverContract, + chainConfig: chainConfig, + ethAPI: ethAPI, + } +} + +func (gc *GenesisContractsClient) CommitState( + event *EventRecordWithTime, + state *state.StateDB, + header *types.Header, + chCtx chainContext, +) error { + eventRecord := event.BuildEventRecord() + recordBytes, err := rlp.EncodeToBytes(eventRecord) + if err != nil { + return err + } + method := "commitState" + t := event.Time.Unix() + data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes) + if err != nil { + log.Error("Unable to pack tx for commitState", "error", err) + return err + } + log.Info("→ committing new state", "eventRecord", event.String()) + msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data) + if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil { + return err + } + return nil +} + +func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { + method := "lastStateId" + data, err := gc.stateReceiverABI.Pack(method) + if err != nil { + log.Error("Unable to pack tx for LastStateId", "error", err) + return nil, err + } + + msgData := (hexutil.Bytes)(data) + toAddress := common.HexToAddress(gc.StateReceiverContract) + gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) + result, err := gc.ethAPI.Call(context.Background(), ethapi.CallArgs{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, rpc.BlockNumber(snapshotNumber)) + if err != nil { + return nil, err + } + + var ret = new(*big.Int) + if err := gc.stateReceiverABI.Unpack(ret, method, result); err != nil { + return nil, err + } + return *ret, nil +} diff --git a/consensus/bor/merkle.go b/consensus/bor/merkle.go new file mode 100644 index 0000000000000000000000000000000000000000..bdfbaba9834eb57f23243a049b5f9e40592c31a7 --- /dev/null +++ b/consensus/bor/merkle.go @@ -0,0 +1,48 @@ +package bor + +func appendBytes32(data ...[]byte) []byte { + var result []byte + for _, v := range data { + paddedV, err := convertTo32(v) + if err == nil { + result = append(result, paddedV[:]...) + } + } + return result +} + +func nextPowerOfTwo(n uint64) uint64 { + if n == 0 { + return 1 + } + // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + n-- + n |= n >> 1 + n |= n >> 2 + n |= n >> 4 + n |= n >> 8 + n |= n >> 16 + n |= n >> 32 + n++ + return n +} + +func convertTo32(input []byte) (output [32]byte, err error) { + l := len(input) + if l > 32 || l == 0 { + return + } + copy(output[32-l:], input[:]) + return +} + +func convert(input []([32]byte)) [][]byte { + var output [][]byte + for _, in := range input { + newInput := make([]byte, len(in[:])) + copy(newInput, in[:]) + output = append(output, newInput) + + } + return output +} diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go index 9c525d6df6c5b355e6a403845adbb0cb748f6d17..43a4439fde659a19125d471748768b3d17954d77 100644 --- a/consensus/bor/rest.go +++ b/consensus/bor/rest.go @@ -6,12 +6,16 @@ import ( "io/ioutil" "net/http" "net/url" - "path" + "sort" "time" "github.com/maticnetwork/bor/log" ) +var ( + stateFetchLimit = 50 +) + // ResponseWithHeight defines a response object type that wraps an original // response with a height. type ResponseWithHeight struct { @@ -20,8 +24,9 @@ type ResponseWithHeight struct { } type IHeimdallClient interface { - Fetch(paths ...string) (*ResponseWithHeight, error) - FetchWithRetry(paths ...string) (*ResponseWithHeight, error) + Fetch(path string, query string) (*ResponseWithHeight, error) + FetchWithRetry(path string, query string) (*ResponseWithHeight, error) + FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) } type HeimdallClient struct { @@ -39,33 +44,57 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) { return h, nil } -func (h *HeimdallClient) Fetch(paths ...string) (*ResponseWithHeight, error) { +func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) { + eventRecords := make([]*EventRecordWithTime, 0) + for { + queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit) + log.Info("Fetching state sync events", "queryParams", queryParams) + response, err := h.FetchWithRetry("clerk/event-record/list", queryParams) + if err != nil { + return nil, err + } + var _eventRecords []*EventRecordWithTime + if response.Result == nil { // status 204 + break + } + if err := json.Unmarshal(response.Result, &_eventRecords); err != nil { + return nil, err + } + eventRecords = append(eventRecords, _eventRecords...) + if len(_eventRecords) < stateFetchLimit { + break + } + fromID += uint64(stateFetchLimit) + } + + sort.SliceStable(eventRecords, func(i, j int) bool { + return eventRecords[i].ID < eventRecords[j].ID + }) + return eventRecords, nil +} + +// Fetch fetches response from heimdall +func (h *HeimdallClient) Fetch(rawPath string, rawQuery string) (*ResponseWithHeight, error) { u, err := url.Parse(h.urlString) if err != nil { return nil, err } - for _, e := range paths { - if e != "" { - u.Path = path.Join(u.Path, e) - } - } + u.Path = rawPath + u.RawQuery = rawQuery return h.internalFetch(u) } // FetchWithRetry returns data from heimdall with retry -func (h *HeimdallClient) FetchWithRetry(paths ...string) (*ResponseWithHeight, error) { +func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*ResponseWithHeight, error) { u, err := url.Parse(h.urlString) if err != nil { return nil, err } - for _, e := range paths { - if e != "" { - u.Path = path.Join(u.Path, e) - } - } + u.Path = rawPath + u.RawQuery = rawQuery for { res, err := h.internalFetch(u) @@ -86,18 +115,22 @@ func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) defer res.Body.Close() // check status code - if res.StatusCode != 200 { + if res.StatusCode != 200 && res.StatusCode != 204 { return nil, fmt.Errorf("Error while fetching data from Heimdall") } + // unmarshall data from buffer + var response ResponseWithHeight + if res.StatusCode == 204 { + return &response, nil + } + // get response body, err := ioutil.ReadAll(res.Body) if err != nil { return nil, err } - // unmarshall data from buffer - var response ResponseWithHeight if err := json.Unmarshal(body, &response); err != nil { return nil, err } diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index d2f0e82ff49c047cede16743d2d4cfdae2d33250..2ff7dec0cea12f83140de60e764097d7fbeed35f 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -26,7 +26,6 @@ import ( "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/ethdb" "github.com/maticnetwork/bor/internal/ethapi" - "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/params" ) @@ -87,7 +86,9 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat snap.ethAPI = ethAPI // update total voting power - snap.ValidatorSet.updateTotalVotingPower() + if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil { + return nil, err + } return snap, nil } @@ -153,31 +154,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // check if signer is in validator set if !snap.ValidatorSet.HasAddress(signer.Bytes()) { - return nil, errUnauthorizedSigner + return nil, &UnauthorizedSignerError{number, signer.Bytes()} } - // - // Check validator - // - - validators := snap.ValidatorSet.Validators - // proposer will be the last signer if block is not epoch block - proposer := snap.ValidatorSet.GetProposer().Address - proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) - signerIndex, _ := snap.ValidatorSet.GetByAddress(signer) - limit := len(validators)/2 + 1 - - // temp index - tempIndex := signerIndex - if proposerIndex != tempIndex && limit > 0 { - if tempIndex < proposerIndex { - tempIndex = tempIndex + len(validators) - } - - if tempIndex-proposerIndex > limit { - log.Info("Invalid signer: error while applying headers", "proposerIndex", validators[proposerIndex].Address.Hex(), "signerIndex", validators[signerIndex].Address.Hex()) - return nil, errRecentlySigned - } + if _, err = snap.GetSignerSuccessionNumber(signer); err != nil { + return nil, err } // add recents @@ -185,6 +166,9 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // change validator set and change proposer if number > 0 && (number+1)%s.config.Sprint == 0 { + if err := validateHeaderExtraField(header.Extra); err != nil { + return nil, err + } validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal] // get validators from headers and use that for new validator set @@ -200,6 +184,28 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { return snap, nil } +// GetSignerSuccessionNumber returns the relative position of signer in terms of the in-turn proposer +func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error) { + validators := s.ValidatorSet.Validators + proposer := s.ValidatorSet.GetProposer().Address + proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) + if proposerIndex == -1 { + return -1, &UnauthorizedProposerError{s.Number, proposer.Bytes()} + } + signerIndex, _ := s.ValidatorSet.GetByAddress(signer) + if signerIndex == -1 { + return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()} + } + + tempIndex := signerIndex + if proposerIndex != tempIndex { + if tempIndex < proposerIndex { + tempIndex = tempIndex + len(validators) + } + } + return tempIndex - proposerIndex, nil +} + // signers retrieves the list of authorized signers in ascending order. func (s *Snapshot) signers() []common.Address { sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators)) @@ -209,8 +215,8 @@ func (s *Snapshot) signers() []common.Address { return sigs } -// inturn returns if a signer at a given block height is in-turn or not. -func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 { +// Difficulty returns the difficulty for a particular signer at the current snapshot number +func (s *Snapshot) Difficulty(signer common.Address) uint64 { // if signer is empty if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 { return 1 diff --git a/consensus/bor/validator.go b/consensus/bor/validator.go index 0592ab3b138a279d9bcc43d28feabd25913b5112..dab50e7b2c7eb9efa83d5fbb535d08b36c3e9ced 100644 --- a/consensus/bor/validator.go +++ b/consensus/bor/validator.go @@ -2,7 +2,7 @@ package bor import ( "bytes" - "encoding/json" + // "encoding/json" "errors" "fmt" "math/big" @@ -13,8 +13,6 @@ import ( ) // Validator represets Volatile state for each Validator -// NOTE: The ProposerPriority is not included in Validator.Hash(); -// make sure to update that method if changes are made here type Validator struct { ID uint64 `json:"ID"` Address common.Address `json:"signer"` @@ -31,18 +29,23 @@ func NewValidator(address common.Address, votingPower int64) *Validator { } } -// Creates a new copy of the validator so we can mutate ProposerPriority. +// Copy creates a new copy of the validator so we can mutate ProposerPriority. // Panics if the validator is nil. func (v *Validator) Copy() *Validator { vCopy := *v return &vCopy } -// Returns the one with higher ProposerPriority. -func (v *Validator) CompareProposerPriority(other *Validator) *Validator { +// Cmp returns the one validator with a higher ProposerPriority. +// If ProposerPriority is same, it returns the validator with lexicographically smaller address +func (v *Validator) Cmp(other *Validator) *Validator { + // if both of v and other are nil, nil will be returned and that could possibly lead to nil pointer dereference bubbling up the stack if v == nil { return other } + if other == nil { + return v + } if v.ProposerPriority > other.ProposerPriority { return v } else if v.ProposerPriority < other.ProposerPriority { @@ -55,7 +58,6 @@ func (v *Validator) CompareProposerPriority(other *Validator) *Validator { return other } else { panic("Cannot compare identical validators") - return nil } } } @@ -80,18 +82,6 @@ func ValidatorListString(vals []*Validator) string { return strings.Join(chunks, ",") } -// Bytes computes the unique encoding of a validator with a given voting power. -// These are the bytes that gets hashed in consensus. It excludes address -// as its redundant with the pubkey. This also excludes ProposerPriority -// which changes every round. -func (v *Validator) Bytes() []byte { - b, err := json.Marshal(v) - if err != nil { - return b - } - return nil -} - // HeaderBytes return header bytes func (v *Validator) HeaderBytes() []byte { result := make([]byte, 40) diff --git a/consensus/bor/validator_set.go b/consensus/bor/validator_set.go index 2f22d5b59f389460c62a95a93b44ba0aba0bee7f..dbe987ce780dedc3fe1b96d0b5a86d0b757409f7 100644 --- a/consensus/bor/validator_set.go +++ b/consensus/bor/validator_set.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/log" ) // MaxTotalVotingPower - the maximum allowed total voting power. @@ -182,7 +183,7 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 { func (vals *ValidatorSet) getValWithMostPriority() *Validator { var res *Validator for _, val := range vals.Validators { - res = res.CompareProposerPriority(val) + res = res.Cmp(val) } return res } @@ -256,28 +257,29 @@ func (vals *ValidatorSet) Size() int { } // Force recalculation of the set's total voting power. -func (vals *ValidatorSet) updateTotalVotingPower() { +func (vals *ValidatorSet) updateTotalVotingPower() error { sum := int64(0) for _, val := range vals.Validators { // mind overflow sum = safeAddClip(sum, val.VotingPower) if sum > MaxTotalVotingPower { - panic(fmt.Sprintf( - "Total voting power should be guarded to not exceed %v; got: %v", - MaxTotalVotingPower, - sum)) + return &TotalVotingPowerExceededError{sum, vals.Validators} } } - vals.totalVotingPower = sum + return nil } // TotalVotingPower returns the sum of the voting powers of all validators. // It recomputes the total voting power if required. func (vals *ValidatorSet) TotalVotingPower() int64 { if vals.totalVotingPower == 0 { - vals.updateTotalVotingPower() + log.Info("invoking updateTotalVotingPower before returning it") + if err := vals.updateTotalVotingPower(); err != nil { + // Can/should we do better? + panic(err) + } } return vals.totalVotingPower } @@ -298,7 +300,7 @@ func (vals *ValidatorSet) findProposer() *Validator { var proposer *Validator for _, val := range vals.Validators { if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) { - proposer = proposer.CompareProposerPriority(val) + proposer = proposer.Cmp(val) } } return proposer @@ -562,7 +564,9 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes vals.applyUpdates(updates) vals.applyRemovals(deletes) - vals.updateTotalVotingPower() + if err := vals.updateTotalVotingPower(); err != nil { + return err + } // Scale and center. vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower()) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index b90f61176647554ead76da13b30215d89416a91d..799ee16b2dac4521c6459dab1269fc4158ed4a5f 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -26,6 +26,7 @@ import ( "sync" "time" + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/common/hexutil" @@ -39,7 +40,6 @@ import ( "github.com/maticnetwork/bor/params" "github.com/maticnetwork/bor/rlp" "github.com/maticnetwork/bor/rpc" - lru "github.com/hashicorp/golang-lru" "golang.org/x/crypto/sha3" ) diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 593dfe8b997b17c9c8b8100e02d309cdb47bde53..a4063e351695ac59dd7d1c1706b0a5810299f951 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -22,12 +22,12 @@ import ( "sort" "time" + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/ethdb" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/params" - lru "github.com/hashicorp/golang-lru" ) // Vote represents a single vote that an authorized signer made to modify the diff --git a/consensus/errors.go b/consensus/errors.go index a005c5f63de802cbb2bf54203257d23fe16a3109..04342bea8a7c8a6e9ef9959b4d215fa7a04955ad 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -31,6 +31,9 @@ var ( // to the current node. ErrFutureBlock = errors.New("block in the future") + // ErrBlockTooSoon is returned when the period / producerDelay values in the genesis were not respected + ErrBlockTooSoon = errors.New("block was produced sooner than expected") + // ErrInvalidNumber is returned if a block's number doesn't equal it's parent's // plus one. ErrInvalidNumber = errors.New("invalid block number") diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 999d92012ac5532558521468dc95b4e960d895e0..08a80ae8195d11a1d6628018e7d11be26c3d2ed3 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -34,13 +34,13 @@ import ( "unsafe" mmap "github.com/edsrzf/mmap-go" + "github.com/hashicorp/golang-lru/simplelru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/metrics" "github.com/maticnetwork/bor/rpc" - "github.com/hashicorp/golang-lru/simplelru" ) var ErrInvalidDumpMagic = errors.New("invalid dump magic") diff --git a/core/headerchain.go b/core/headerchain.go index 95634891fe7d3d2a523aeb5a6a1b55b48c9e907e..07775a228ac43cf27ce384004574773f93dd7547 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -26,6 +26,7 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus" "github.com/maticnetwork/bor/core/rawdb" @@ -33,7 +34,6 @@ import ( "github.com/maticnetwork/bor/ethdb" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/params" - lru "github.com/hashicorp/golang-lru" ) const ( diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 868d81f6a518bf704629931f52c6a4538a736ab8..33c1ca8b34a2b7278a5a0b6ce9bb78cd0aafc818 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -26,10 +26,10 @@ import ( "sync" "sync/atomic" + "github.com/golang/snappy" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/metrics" - "github.com/golang/snappy" ) var ( diff --git a/core/state/database.go b/core/state/database.go index 834e8ad96b45145932884a9387800cb6f5a8b347..33ab998c611e1277799b2a6fec8ca3059df54777 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -19,10 +19,10 @@ package state import ( "fmt" + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/ethdb" "github.com/maticnetwork/bor/trie" - lru "github.com/hashicorp/golang-lru" ) const ( diff --git a/core/tx_pool.go b/core/tx_pool.go index 02011586c3443c766fb571fa8d02f6208d9ab185..a1822ec54a033436857155cc3400dc649b4d61d9 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -117,12 +117,6 @@ const ( TxStatusIncluded ) -// bor acts as a way to be able to type cast consensus.Engine; -// since importing "github.com/maticnetwork/bor/consensus/bor" results in a cyclic dependency -type bor interface { - IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool -} - // blockChain provides the state of blockchain and current gas limit to do // some pre checks in tx pool and event subscribers. type blockChain interface { @@ -537,7 +531,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network if !local && - !pool.chain.Engine().(bor).IsValidatorAction(pool.chain.(consensus.ChainReader), from, tx) && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { return ErrUnderpriced } diff --git a/dashboard/assets/yarn.lock b/dashboard/assets/yarn.lock index 0fdf5593cddf3f8b8803452a6fcc5b5196800af1..a1b03f483bcd7b1b4c5d17face001eeb279df9df 100644 --- a/dashboard/assets/yarn.lock +++ b/dashboard/assets/yarn.lock @@ -1075,7 +1075,7 @@ after@0.8.2: resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= -agent-base@4, agent-base@^4.1.0: +agent-base@4, agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== @@ -3650,11 +3650,11 @@ https-browserify@^1.0.0: integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= https-proxy-agent@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" - integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" humps@^2.0.1: diff --git a/eth/api_backend.go b/eth/api_backend.go index ff03d1a91e0537368b4c8ad9f10c07e916ef819a..0be0376cf556b9b9916aa8da2a7dca9699c01b01 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -248,3 +248,17 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) } } + +func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + var api *bor.API + for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) { + if _api.Namespace == "bor" { + api = _api.Service.(*bor.API) + } + } + root, err := api.GetRootHash(starBlockNr, endBlockNr) + if err != nil { + return "", err + } + return root, nil +} diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 5d349a289b86f8875b4e59d4b38cdf22778a2f6f..7d44b0da034b1c5373fc2259308c637563c7e806 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -522,6 +522,15 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data)) } +// GetRootHash returns the merkle root of the block headers +func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64) (string, error) { + var rootHash string + if err := ec.c.CallContext(ctx, &rootHash, "eth_getRootHash", startBlockNumber, endBlockNumber); err != nil { + return "", err + } + return rootHash, nil +} + func toCallArg(msg ethereum.CallMsg) interface{} { arg := map[string]interface{}{ "from": msg.From, diff --git a/go.mod b/go.mod index ca433a71c6e86be991aa6fc41768bd611f3d735e..efce11a0bf9f85afb93992b53e0a8f53161a7f88 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 + github.com/xsleonard/go-merkle v1.1.0 golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 golang.org/x/net v0.0.0-20200301022130-244492dfa37a golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e diff --git a/go.sum b/go.sum index c51ed2d8e957a19c286f02059467ee6d93ff1938..c15b30bb97f700cbf66266ae02be6fb655867871 100644 --- a/go.sum +++ b/go.sum @@ -176,6 +176,8 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg= +github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA= diff --git a/graphql/service.go b/graphql/service.go index 473e01b250aacd39715a0f96093252d4dedf10d2..6b2626d927000140133a5705220402a4de58a81a 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -21,12 +21,12 @@ import ( "net" "net/http" + "github.com/graph-gophers/graphql-go" + "github.com/graph-gophers/graphql-go/relay" "github.com/maticnetwork/bor/internal/ethapi" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/p2p" "github.com/maticnetwork/bor/rpc" - "github.com/graph-gophers/graphql-go" - "github.com/graph-gophers/graphql-go/relay" ) // Service encapsulates a GraphQL service. diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 8bd64b9bb939dbd1ef1033df4915e680ea12652c..469dd8dff2a8adbb9d4e6782963913f17505a110 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -24,10 +24,10 @@ import ( "os" "runtime" + "github.com/fjl/memsize/memsizeui" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/metrics" "github.com/maticnetwork/bor/metrics/exp" - "github.com/fjl/memsize/memsizeui" colorable "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "gopkg.in/urfave/cli.v1" diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2a939ed2c463f6d81a3d249a6d45afffd50d95a9..cee5a575fb45cd30e27f4f2d9b4ed15c454e4875 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -716,6 +716,14 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A return res[:], state.Error() } +func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + root, err := s.b.GetRootHash(ctx, starBlockNr, endBlockNr) + if err != nil { + return "", err + } + return root, nil +} + // CallArgs represents the arguments for a call. type CallArgs struct { From *common.Address `json:"from"` diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index e0deeab81fdb42e2c907b223fe1469d085b52866..595a69b0cc2ebd6579b298e4aa01c15a6b76bec5 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -62,6 +62,7 @@ type Backend interface { SubscribeStateEvent(ch chan<- core.NewStateChangeEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription + GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) // Transaction pool API SendTx(ctx context.Context, signedTx *types.Transaction) error diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index d3fea7b50cc52366df901f91d244f686f11e2841..9ee4b4f3a7a46ceaf19b8c8afc51eca8b0b2f5bb 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -149,6 +149,11 @@ web3._extend({ call: 'bor_getCurrentValidators', params: 0 }), + new web3._extend.Method({ + name: 'getRootHash', + call: 'bor_getRootHash', + params: 2, + }), ] }); ` diff --git a/les/api_backend.go b/les/api_backend.go index 5c8ec82d8812f6c828364e2d4a44334ebb163371..3b228e7374625e5a23c82ebb706372969ee8439c 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -223,3 +223,7 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) } } + +func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + return "", errors.New("Not implemented") +} diff --git a/light/lightchain.go b/light/lightchain.go index cfa684e84624bd81221bcb0b5651d21d02660094..99f14ee3caa60140b78404fd3b3c9a865a570838 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -26,6 +26,7 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus" "github.com/maticnetwork/bor/core" @@ -37,7 +38,6 @@ import ( "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/params" "github.com/maticnetwork/bor/rlp" - lru "github.com/hashicorp/golang-lru" ) var ( diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index 5971c50aa3b525b54582897c4f89d3070534d717..d4452bc6d35fcc63080976900c415a5fe7a6ee6d 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -5,9 +5,9 @@ import ( uurl "net/url" "time" + "github.com/influxdata/influxdb/client" "github.com/maticnetwork/bor/log" "github.com/maticnetwork/bor/metrics" - "github.com/influxdata/influxdb/client" ) type reporter struct { diff --git a/mocks/IHeimdallClient.go b/mocks/IHeimdallClient.go index cb09800c746d629e87e0cb52269b3be23be0c7ea..d6037d2162de114cfa0905e9fd7a79fe424de8cd 100644 --- a/mocks/IHeimdallClient.go +++ b/mocks/IHeimdallClient.go @@ -12,19 +12,13 @@ type IHeimdallClient struct { mock.Mock } -// Fetch provides a mock function with given fields: paths -func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, error) { - _va := make([]interface{}, len(paths)) - for _i := range paths { - _va[_i] = paths[_i] - } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// Fetch provides a mock function with given fields: path, query +func (_m *IHeimdallClient) Fetch(path string, query string) (*bor.ResponseWithHeight, error) { + ret := _m.Called(path, query) var r0 *bor.ResponseWithHeight - if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok { - r0 = rf(paths...) + if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok { + r0 = rf(path, query) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*bor.ResponseWithHeight) @@ -32,8 +26,8 @@ func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, erro } var r1 error - if rf, ok := ret.Get(1).(func(...string) error); ok { - r1 = rf(paths...) + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(path, query) } else { r1 = ret.Error(1) } @@ -41,19 +35,36 @@ func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, erro return r0, r1 } -// FetchWithRetry provides a mock function with given fields: paths -func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHeight, error) { - _va := make([]interface{}, len(paths)) - for _i := range paths { - _va[_i] = paths[_i] +// FetchStateSyncEvents provides a mock function with given fields: fromID, to +func (_m *IHeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*bor.EventRecordWithTime, error) { + ret := _m.Called(fromID, to) + + var r0 []*bor.EventRecordWithTime + if rf, ok := ret.Get(0).(func(uint64, int64) []*bor.EventRecordWithTime); ok { + r0 = rf(fromID, to) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*bor.EventRecordWithTime) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(uint64, int64) error); ok { + r1 = rf(fromID, to) + } else { + r1 = ret.Error(1) } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) + + return r0, r1 +} + +// FetchWithRetry provides a mock function with given fields: path, query +func (_m *IHeimdallClient) FetchWithRetry(path string, query string) (*bor.ResponseWithHeight, error) { + ret := _m.Called(path, query) var r0 *bor.ResponseWithHeight - if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok { - r0 = rf(paths...) + if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok { + r0 = rf(path, query) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*bor.ResponseWithHeight) @@ -61,8 +72,8 @@ func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHei } var r1 error - if rf, ok := ret.Get(1).(func(...string) error); ok { - r1 = rf(paths...) + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(path, query) } else { r1 = ret.Error(1) } diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 08b7a39ddaf91ea2305f64cff4e53055e66191ba..0f5cd07c050515a47794c2bf9d8127a0fae6484b 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -25,8 +25,8 @@ import ( "sync" "time" - "github.com/maticnetwork/bor/log" "github.com/jackpal/go-nat-pmp" + "github.com/maticnetwork/bor/log" ) // An implementation of nat.Interface can map local ports to ports diff --git a/p2p/rlpx.go b/p2p/rlpx.go index 1513ed9d09fb95883a75fc1e737cb439990d6d85..36f845332fb5ea144d93e5cf8cc080b4427a2731 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -35,11 +35,11 @@ import ( "sync" "time" + "github.com/golang/snappy" "github.com/maticnetwork/bor/common/bitutil" "github.com/maticnetwork/bor/crypto" "github.com/maticnetwork/bor/crypto/ecies" "github.com/maticnetwork/bor/rlp" - "github.com/golang/snappy" "golang.org/x/crypto/sha3" ) diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index c42f2e8a0c67f37df7aa08b166ae1844ae843814..55119851f289e29d0be3c2f8106f0d1bdca45592 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -29,12 +29,12 @@ import ( "strings" "sync" + "github.com/julienschmidt/httprouter" "github.com/maticnetwork/bor/event" "github.com/maticnetwork/bor/p2p" "github.com/maticnetwork/bor/p2p/enode" "github.com/maticnetwork/bor/p2p/simulations/adapters" "github.com/maticnetwork/bor/rpc" - "github.com/julienschmidt/httprouter" "golang.org/x/net/websocket" ) diff --git a/params/config.go b/params/config.go index e56336fe2d5f6d01a12c247f6ca846817d6eb251..3af6bb064becce65bc2a228232bf740163c3ae3c 100644 --- a/params/config.go +++ b/params/config.go @@ -319,6 +319,7 @@ type BorConfig struct { Period uint64 `json:"period"` // Number of seconds between blocks to enforce ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval Sprint uint64 `json:"sprint"` // Epoch length to proposer + BackupMultiplier uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time ValidatorContract string `json:"validatorContract"` // Validator set contract StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract }