diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 5973a8cebc..f4dd814f97 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -108,10 +108,12 @@ func (w *wizard) makeGenesis() { genesis.Difficulty = big.NewInt(1) genesis.GasLimit = 10000000 genesis.Config.Bor = ¶ms.BorConfig{ - Period: 1, - ProducerDelay: 5, - Sprint: 60, - ValidatorContract: "0x0000000000000000000000000000000000001000", + Period: 1, + ProducerDelay: 5, + Sprint: 60, + ValidatorContract: "0x0000000000000000000000000000000000001000", + StateReceiverContract: "0x0000000000000000000000000000000000001001", + Heimdall: "http://localhost:1317", } // We also need the initial list of signers diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 60569caec5..da739abd7b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1670,7 +1670,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 { - engine = bor.New(config.Bor, chainDb, nil) + engine = bor.New(config, chainDb, nil) } else { engine = ethash.NewFaker() if !ctx.GlobalBool(FakePoWFlag.Name) { diff --git a/consensus/bor/api.go b/consensus/bor/api.go index da6ef1bdc0..3e9cf87fa2 100644 --- a/consensus/bor/api.go +++ b/consensus/bor/api.go @@ -87,33 +87,3 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { } return snap.signers(), nil } - -// Proposals returns the current proposals the node tries to uphold and vote on. -func (api *API) Proposals() map[common.Address]bool { - api.bor.lock.RLock() - defer api.bor.lock.RUnlock() - - proposals := make(map[common.Address]bool) - for address, auth := range api.bor.proposals { - proposals[address] = auth - } - return proposals -} - -// Propose injects a new authorization proposal that the signer will attempt to -// push through. -func (api *API) Propose(address common.Address, auth bool) { - api.bor.lock.Lock() - defer api.bor.lock.Unlock() - - api.bor.proposals[address] = auth -} - -// Discard drops a currently running proposal, stopping the signer from casting -// further votes (either for or against). -func (api *API) Discard(address common.Address) { - api.bor.lock.Lock() - defer api.bor.lock.Unlock() - - delete(api.bor.proposals, address) -} diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 2c2fcf020f..f2d8e43772 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -3,24 +3,31 @@ package bor import ( "bytes" "context" + "encoding/hex" + "encoding/json" "errors" "fmt" "io" "math" "math/big" + "net/http" "sort" + "strconv" "strings" "sync" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -33,7 +40,8 @@ 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":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"commitSpan","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":"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 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 @@ -56,6 +64,7 @@ var ( diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures validatorHeaderBytesLength = common.AddressLength + 20 // address + power + systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") ) // Various error messages to mark blocks invalid. These should be private to @@ -197,16 +206,9 @@ func CalcDifficulty(snap *Snapshot, signer common.Address, epoch uint64) *big.In // CalcProducerDelay is the producer delay algorithm based on block time. func CalcProducerDelay(snap *Snapshot, signer common.Address, period uint64, epoch uint64, producerDelay uint64) uint64 { - // lastSigner := snap.Recents[snap.Number] - // proposer := snap.ValidatorSet.GetProposer() - // if block is epoch start block, proposer will be inturn signer if (snap.Number+1)%epoch == 0 { return producerDelay - - // if block is not epoch block, last block signer will be inturn - // } else if bytes.Compare(lastSigner.Bytes(), signer.Bytes()) != 0 { - // return producerDelay } return period @@ -227,46 +229,59 @@ func BorRLP(header *types.Header) []byte { // Bor is the matic-bor consensus engine type Bor struct { - config *params.BorConfig // Consensus engine configuration parameters for bor consensus - db ethdb.Database // Database to store and retrieve snapshot checkpoints + chainConfig *params.ChainConfig // Chain config + config *params.BorConfig // Consensus engine configuration parameters for bor consensus + db ethdb.Database // Database to store and retrieve snapshot checkpoints recents *lru.ARCCache // Snapshots for recent block to speed up reorgs signatures *lru.ARCCache // Signatures of recent blocks to speed up mining - proposals map[common.Address]bool // Current list of proposals we are pushing - signer common.Address // Ethereum address of the signing key signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - ethAPI *ethapi.PublicBlockChainAPI - validatorSetABI abi.ABI + ethAPI *ethapi.PublicBlockChainAPI + validatorSetABI abi.ABI + stateReceiverABI abi.ABI + httpClient http.Client // The fields below are for testing only fakeDiff bool // Skip difficulty verifications } // New creates a Matic Bor consensus engine. -func New(config *params.BorConfig, db ethdb.Database, ethAPI *ethapi.PublicBlockChainAPI) *Bor { +func New( + chainConfig *params.ChainConfig, + db ethdb.Database, + ethAPI *ethapi.PublicBlockChainAPI, +) *Bor { + // get bor config + borConfig := chainConfig.Bor + // Set any missing consensus parameters to their defaults - conf := *config - if conf.Sprint == 0 { - conf.Sprint = defaultSprintLength + if borConfig != nil && borConfig.Sprint == 0 { + borConfig.Sprint = defaultSprintLength } // Allocate the snapshot caches and create the engine recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySignatures) vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) + sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) c := &Bor{ - config: &conf, - db: db, - ethAPI: ethAPI, - recents: recents, - signatures: signatures, - proposals: make(map[common.Address]bool), - validatorSetABI: vABI, + chainConfig: chainConfig, + config: borConfig, + db: db, + ethAPI: ethAPI, + recents: recents, + signatures: signatures, + validatorSetABI: vABI, + stateReceiverABI: sABI, + httpClient: http.Client{ + Timeout: time.Duration(5 * time.Second), + }, } + return c } @@ -450,7 +465,7 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H // get checkpoint data hash := checkpoint.Hash() - // current validators + // get validators and current span validators, err := c.GetCurrentValidators(number, number+1) if err != nil { return nil, err @@ -646,6 +661,23 @@ 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 + if header.Number.Uint64()%c.config.Sprint == 0 { + cx := chainContext{Chain: chain, Bor: c} + + // check and commit span + if err := c.checkAndCommitSpan(state, header, cx); err != nil { + fmt.Println("Error while committing span", err) + return + } + + // commit statees + if err := c.CommitStates(state, header, cx); err != nil { + fmt.Println("Error while committing states", err) + return + } + } + // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) @@ -654,6 +686,24 @@ 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 { + cx := chainContext{Chain: chain, Bor: c} + + // check and commit span + err := c.checkAndCommitSpan(state, header, cx) + if err != nil { + fmt.Println("Error while committing span", err) + return nil, err + } + + // commit statees + if err := c.CommitStates(state, header, cx); err != nil { + fmt.Println("Error while committing states", err) + // return nil, err + } + } + // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) @@ -790,23 +840,101 @@ func (c *Bor) Close() error { return nil } -// GetCurrentValidators get current validators -func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([]*Validator, error) { - return GetValidators(snapshotNumber, blockNumber, c.config.Sprint, c.config.ValidatorContract, c.ethAPI) +// 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 { + fmt.Println("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 } -// GetValidators get current validators -func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, validatorContract string, ethAPI *ethapi.PublicBlockChainAPI) ([]*Validator, error) { +// GetCurrentSpan get current span from contract +func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) { // block blockNr := rpc.BlockNumber(snapshotNumber) - // validator set ABI - validatorSetABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) + // method + method := "getCurrentSpan" + + data, err := c.validatorSetABI.Pack(method) + if err != nil { + fmt.Println("Unable to pack tx for getCurrentSpan", "error", err) + 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{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, blockNr) + if err != nil { + return nil, err + } + + // span result + ret := new(struct { + Number *big.Int + StartBlock *big.Int + EndBlock *big.Int + }) + if err := c.validatorSetABI.Unpack(ret, method, result); err != nil { + return nil, err + } + + // create new span + span := Span{ + ID: ret.Number.Uint64(), + StartBlock: ret.StartBlock.Uint64(), + EndBlock: ret.EndBlock.Uint64(), + } + + return &span, nil +} + +// GetCurrentValidators get current validators +func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([]*Validator, error) { + // block + blockNr := rpc.BlockNumber(snapshotNumber) // method method := "getBorValidators" - data, err := validatorSetABI.Pack(method, big.NewInt(0).SetUint64(blockNumber)) + data, err := c.validatorSetABI.Pack(method, big.NewInt(0).SetUint64(blockNumber)) if err != nil { fmt.Println("Unable to pack tx for getValidator", "error", err) return nil, err @@ -817,9 +945,9 @@ func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, val // call msgData := (hexutil.Bytes)(data) - toAddress := common.HexToAddress(validatorContract) + toAddress := common.HexToAddress(c.config.ValidatorContract) gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) - result, err := ethAPI.Call(ctx, ethapi.CallArgs{ + result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ Gas: &gas, To: &toAddress, Data: &msgData, @@ -838,7 +966,7 @@ func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, val ret1, } - if err := validatorSetABI.Unpack(out, method, result); err != nil { + if err := c.validatorSetABI.Unpack(out, method, result); err != nil { return nil, err } @@ -853,6 +981,297 @@ func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, val return valz, nil } +func (c *Bor) checkAndCommitSpan( + state *state.StateDB, + header *types.Header, + chain core.ChainContext, +) error { + pending := false + var span *Span = nil + var wg sync.WaitGroup + wg.Add(1) + go func() { + pending, _ = c.isSpanPending(header.Number.Uint64()) + wg.Done() + }() + + wg.Add(1) + go func() { + span, _ = c.GetCurrentSpan(header.Number.Uint64() - 1) + wg.Done() + }() + + wg.Wait() + + // commit span if there is new span pending or span is ending or end block is not set + if pending || c.needToCommitSpan(span, header) { + err := c.commitSpan(span, state, header, chain) + return err + } + + return nil +} + +func (c *Bor) needToCommitSpan(span *Span, header *types.Header) bool { + // if span is nil + if span == nil { + return false + } + + // check span is not set initially + if span.EndBlock == 0 { + return true + } + + // if current block is first block of last sprint in current span + h := header.Number.Uint64() + if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == h { + return true + } + + return false +} + +func (c *Bor) commitSpan( + span *Span, + state *state.StateDB, + header *types.Header, + chain core.ChainContext, +) error { + response, err := FetchFromHeimdall(c.httpClient, c.chainConfig.Bor.Heimdall, "bor", "span", strconv.FormatUint(span.ID+1, 10)) + if err != nil { + return err + } + + var heimdallSpan HeimdallSpan + if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil { + return err + } + + // get validators bytes + var validators []MinimalVal + for _, val := range heimdallSpan.ValidatorSet.Validators { + validators = append(validators, val.MinimalVal()) + } + validatorBytes, err := rlp.EncodeToBytes(validators) + if err != nil { + return err + } + + // get producers bytes + var producers []MinimalVal + for _, val := range heimdallSpan.SelectedProducers { + producers = append(producers, val.MinimalVal()) + } + producerBytes, err := rlp.EncodeToBytes(producers) + if err != nil { + return err + } + + // method + method := "commitSpan" + + fmt.Println( + "id", heimdallSpan.ID, + "startBlock", heimdallSpan.StartBlock, + "endBlock", heimdallSpan.EndBlock, + "validatorBytes", hex.EncodeToString(validatorBytes), + "producerBytes", hex.EncodeToString(producerBytes), + ) + + // get packed data + data, err := c.validatorSetABI.Pack(method, + big.NewInt(0).SetUint64(heimdallSpan.ID), + big.NewInt(0).SetUint64(heimdallSpan.StartBlock), + big.NewInt(0).SetUint64(heimdallSpan.EndBlock), + validatorBytes, + producerBytes, + ) + if err != nil { + fmt.Println("Unable to pack tx for commitSpan", "error", err) + return err + } + + // get system message + msg := getSystemMessage(common.HexToAddress(c.config.ValidatorContract), data) + + // apply message + return applyMessage(msg, state, header, c.chainConfig, chain) +} + +// GetPendingStateProposals get pending state proposals +func (c *Bor) GetPendingStateProposals(snapshotNumber uint64) ([]*big.Int, error) { + // block + blockNr := rpc.BlockNumber(snapshotNumber) + + // method + method := "getPendingStates" + + data, err := c.stateReceiverABI.Pack(method) + if err != nil { + fmt.Println("Unable to pack tx for getPendingStates", "error", err) + 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{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, blockNr) + if err != nil { + return nil, err + } + + var ret = new([]*big.Int) + if err := c.stateReceiverABI.Unpack(ret, method, result); err != nil { + return nil, err + } + + return *ret, nil +} + +// CommitStates commit states +func (c *Bor) CommitStates( + state *state.StateDB, + header *types.Header, + chain core.ChainContext, +) error { + // get pending state proposals + stateIds, err := c.GetPendingStateProposals(header.Number.Uint64() - 1) + if err != nil { + return err + } + + // state ids + if len(stateIds) > 0 { + fmt.Println("Found new proposed states", len(stateIds)) + } + + method := "commitState" + + // itereate through state ids + for _, stateID := range stateIds { + // fetch from heimdall + response, err := FetchFromHeimdall(c.httpClient, c.chainConfig.Bor.Heimdall, "clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10)) + if err != nil { + return err + } + + // get event record + var eventRecord EventRecord + if err := json.Unmarshal(response.Result, &eventRecord); err != nil { + return err + } + + 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 { + fmt.Println("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 { + return err + } + } + + return nil +} + +// +// Private methods +// + +// +// Chain context +// + +// chain context +type chainContext struct { + Chain consensus.ChainReader + Bor consensus.Engine +} + +func (c chainContext) Engine() consensus.Engine { + return c.Bor +} + +func (c chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { + return c.Chain.GetHeader(hash, number) +} + +// callmsg implements core.Message to allow passing it as a transaction simulator. +type callmsg struct { + ethereum.CallMsg +} + +func (m callmsg) From() common.Address { return m.CallMsg.From } +func (m callmsg) Nonce() uint64 { return 0 } +func (m callmsg) CheckNonce() bool { return false } +func (m callmsg) To() *common.Address { return m.CallMsg.To } +func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } +func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } +func (m callmsg) Value() *big.Int { return m.CallMsg.Value } +func (m callmsg) Data() []byte { return m.CallMsg.Data } + +// get system message +func getSystemMessage(toAddress common.Address, data []byte) callmsg { + return callmsg{ + ethereum.CallMsg{ + From: systemAddress, + Gas: math.MaxUint64 / 2, + GasPrice: big.NewInt(0), + Value: big.NewInt(0), + To: &toAddress, + Data: data, + }, + } +} + +// apply message +func applyMessage( + msg callmsg, + state *state.StateDB, + header *types.Header, + chainConfig *params.ChainConfig, + chainContext core.ChainContext, +) error { + // Create a new context to be used in the EVM environment + context := core.NewEVMContext(msg, header, chainContext, &header.Coinbase) + // Create a new environment which holds all relevant information + // about the transaction and calling mechanisms. + vmenv := vm.NewEVM(context, state, chainConfig, vm.Config{}) + // Apply the transaction to the current state (included in the env) + _, _, err := vmenv.Call( + vm.AccountRef(msg.From()), + *msg.To(), + msg.Data(), + msg.Gas(), + msg.Value(), + ) + // Update the state with pending changes + if err != nil { + state.Finalise(true) + } + + return nil +} + func validatorContains(a []*Validator, x *Validator) (*Validator, bool) { for _, n := range a { if bytes.Compare(n.Address.Bytes(), x.Address.Bytes()) == 0 { diff --git a/consensus/bor/clerk.go b/consensus/bor/clerk.go new file mode 100644 index 0000000000..70ea4e4664 --- /dev/null +++ b/consensus/bor/clerk.go @@ -0,0 +1,14 @@ +package bor + +import ( + "github.com/ethereum/go-ethereum/common" +) + +// EventRecord represents state record +type EventRecord struct { + ID uint64 `json:"id" yaml:"id"` + Contract common.Address `json:"contract" yaml:"contract"` + Data []byte `json:"data" yaml:"data"` + TxHash common.Hash `json:"tx_hash" yaml:"tx_hash"` + LogIndex uint64 `json:"log_index" yaml:"log_index"` +} diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go new file mode 100644 index 0000000000..f855adc992 --- /dev/null +++ b/consensus/bor/rest.go @@ -0,0 +1,56 @@ +package bor + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path" +) + +// ResponseWithHeight defines a response object type that wraps an original +// response with a height. +type ResponseWithHeight struct { + Height string `json:"height"` + Result json.RawMessage `json:"result"` +} + +// FetchFromHeimdall returns data from heimdall +func FetchFromHeimdall(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) { + u, err := url.Parse(urlString) + if err != nil { + return nil, err + } + + for _, e := range paths { + if e != "" { + u.Path = path.Join(u.Path, e) + } + } + + res, err := client.Get(u.String()) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // check status code + if res.StatusCode != 200 { + return nil, fmt.Errorf("Error while fetching data from Heimdall") + } + + // 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 + } + + return &response, nil +} diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index b55fa8c9ea..41a844eaa5 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -29,22 +29,6 @@ import ( lru "github.com/hashicorp/golang-lru" ) -// Vote represents a single vote that an authorized signer made to modify the -// list of authorizations. -type Vote struct { - Signer common.Address `json:"signer"` // Authorized signer that cast this vote - Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes) - Address common.Address `json:"address"` // Account being voted on to change its authorization - Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account -} - -// Tally is a simple vote tally to keep the current score of votes. Votes that -// go against the proposal aren't counted since it's equivalent to not voting. -type Tally struct { - Authorize bool `json:"authorize"` // Whether the vote is about authorizing or kicking someone - Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal -} - // Snapshot is the state of the authorization voting at a given point in time. type Snapshot struct { config *params.BorConfig // Consensus engine parameters to fine tune behavior @@ -55,8 +39,6 @@ type Snapshot struct { Hash common.Hash `json:"hash"` // Block hash where the snapshot was created ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections - // Votes []*Vote `json:"votes"` // List of votes cast in chronological order - // Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating } // signersAscending implements the sort interface to allow sorting a list of addresses @@ -69,7 +51,14 @@ func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // newSnapshot creates a new snapshot with the specified startup parameters. This // method does not initialize the set of recent signers, so only ever use if for // the genesis block. -func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, validators []*Validator, ethAPI *ethapi.PublicBlockChainAPI) *Snapshot { +func newSnapshot( + config *params.BorConfig, + sigcache *lru.ARCCache, + number uint64, + hash common.Hash, + validators []*Validator, + ethAPI *ethapi.PublicBlockChainAPI, +) *Snapshot { snap := &Snapshot{ config: config, ethAPI: ethAPI, @@ -78,7 +67,6 @@ func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64 Hash: hash, ValidatorSet: NewValidatorSet(validators), Recents: make(map[uint64]common.Address), - // Tally: make(map[common.Address]Tally), } return snap } @@ -122,8 +110,6 @@ func (s *Snapshot) copy() *Snapshot { Hash: s.Hash, ValidatorSet: s.ValidatorSet.Copy(), Recents: make(map[uint64]common.Address), - // Votes: make([]*Vote, len(s.Votes)), - // Tally: make(map[common.Address]Tally), } for block, signer := range s.Recents { cpy.Recents[block] = signer @@ -132,50 +118,6 @@ func (s *Snapshot) copy() *Snapshot { return cpy } -// // validVote returns whether it makes sense to cast the specified vote in the -// // given snapshot context (e.g. don't try to add an already authorized signer). -// func (s *Snapshot) validVote(address common.Address, authorize bool) bool { -// _, signer := s.Signers[address] -// return (signer && !authorize) || (!signer && authorize) -// } - -// // cast adds a new vote into the tally. -// func (s *Snapshot) cast(address common.Address, authorize bool) bool { -// // Ensure the vote is meaningful -// if !s.validVote(address, authorize) { -// return false -// } -// // Cast the vote into an existing or new tally -// if old, ok := s.Tally[address]; ok { -// old.Votes++ -// s.Tally[address] = old -// } else { -// s.Tally[address] = Tally{Authorize: authorize, Votes: 1} -// } -// return true -// } - -// // uncast removes a previously cast vote from the tally. -// func (s *Snapshot) uncast(address common.Address, authorize bool) bool { -// // If there's no tally, it's a dangling vote, just drop -// tally, ok := s.Tally[address] -// if !ok { -// return false -// } -// // Ensure we only revert counted votes -// if tally.Authorize != authorize { -// return false -// } -// // Otherwise revert the vote -// if tally.Votes > 1 { -// tally.Votes-- -// s.Tally[address] = tally -// } else { -// delete(s.Tally, address) -// } -// return true -// } - func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // Allow passing in no headers for cleaner code if len(headers) == 0 { @@ -212,11 +154,14 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { if number > 0 && (number+1)%s.config.Sprint == 0 { validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal] - // newVals, _ := GetValidators(number, number+1, s.config.Sprint, s.config.ValidatorContract, snap.ethAPI) + // get validators from headers and use that for new validator set newVals, _ := ParseValidators(validatorBytes) v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals) v.IncrementProposerPriority(1) snap.ValidatorSet = v + + // log new validator set + fmt.Println("Current validator set", "number", snap.Number, "validatorSet", snap.ValidatorSet) } // check if signer is in validator set @@ -231,9 +176,6 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { validators := snap.ValidatorSet.Validators // proposer will be the last signer if block is not epoch block proposer := snap.ValidatorSet.GetProposer().Address - // if number%s.config.Sprint != 0 { - // proposer = snap.Recents[number-1] - // } proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) signerIndex, _ := snap.ValidatorSet.GetByAddress(signer) limit := len(validators) - (len(validators)/2 + 1) @@ -252,14 +194,10 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // add recents snap.Recents[number] = signer - // TODO remove - fmt.Println("Recent signer", "number", number, "signer", signer.Hex()) } snap.Number += uint64(len(headers)) snap.Hash = headers[len(headers)-1].Hash() - fmt.Println("Current validator set", "number", snap.Number, "validatorSet", snap.ValidatorSet) - return snap, nil } @@ -283,11 +221,6 @@ func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) ui proposer := s.ValidatorSet.GetProposer().Address totalValidators := len(validators) - // proposer will be the last signer if block is not epoch block - // proposer := snap.ValidatorSet.GetProposer().Address - // if number%epoch != 0 { - // proposer = snap.Recents[number-1] - // } proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) signerIndex, _ := s.ValidatorSet.GetByAddress(signer) @@ -298,21 +231,4 @@ func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) ui } return uint64(totalValidators - (tempIndex - proposerIndex)) - - // signers, offset := s.signers(), 0 - // for offset < len(signers) && signers[offset] != signer { - // offset++ - // } - // return ((number / producerPeriod) % uint64(len(signers))) == uint64(offset) - - // // if block is epoch start block, proposer will be inturn signer - // if s.Number%epoch == 0 { - // if bytes.Compare(proposer.Address.Bytes(), signer.Bytes()) == 0 { - // return true - // } - // // if block is not epoch block, last block signer will be inturn - // } else if bytes.Compare(lastSigner.Bytes(), signer.Bytes()) == 0 { - // return false - // } - // return false } diff --git a/consensus/bor/span.go b/consensus/bor/span.go new file mode 100644 index 0000000000..2fd0cf1079 --- /dev/null +++ b/consensus/bor/span.go @@ -0,0 +1,16 @@ +package bor + +// Span represents a current bor span +type Span struct { + ID uint64 `json:"span_id" yaml:"span_id"` + StartBlock uint64 `json:"start_block" yaml:"start_block"` + EndBlock uint64 `json:"end_block" yaml:"end_block"` +} + +// HeimdallSpan represents span from heimdall APIs +type HeimdallSpan struct { + Span + ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"` + SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"` + ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"` +} diff --git a/consensus/bor/validator.go b/consensus/bor/validator.go index 32934ea2d4..50b4a58ae4 100644 --- a/consensus/bor/validator.go +++ b/consensus/bor/validator.go @@ -6,20 +6,23 @@ import ( "errors" "fmt" "math/big" + "sort" "strings" "github.com/ethereum/go-ethereum/common" ) -// Volatile state for each Validator +// 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 { - Address common.Address `json:"address"` - VotingPower int64 `json:"voting_power"` - ProposerPriority int64 `json:"proposer_priority"` + ID uint64 `json:"ID"` + Address common.Address `json:"signer"` + VotingPower int64 `json:"power"` + ProposerPriority int64 `json:"accum"` } +// NewValidator creates new validator func NewValidator(address common.Address, votingPower int64) *Validator { return &Validator{ Address: address, @@ -105,6 +108,15 @@ func (v *Validator) PowerBytes() []byte { return result } +// MinimalVal returns block number of last validator update +func (v *Validator) MinimalVal() MinimalVal { + return MinimalVal{ + ID: v.ID, + VotingPower: uint64(v.VotingPower), + Signer: v.Address, + } +} + // ParseValidators returns validator set bytes func ParseValidators(validatorsBytes []byte) ([]*Validator, error) { if len(validatorsBytes)%40 != 0 { @@ -124,3 +136,29 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) { return result, nil } + +// --- + +// MinimalVal is the minimal validator representation +// Used to send validator information to bor validator contract +type MinimalVal struct { + ID uint64 `json:"ID"` + VotingPower uint64 `json:"power"` // TODO add 10^-18 here so that we dont overflow easily + Signer common.Address `json:"signer"` +} + +// SortMinimalValByAddress sorts validators +func SortMinimalValByAddress(a []MinimalVal) []MinimalVal { + sort.Slice(a, func(i, j int) bool { + return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0 + }) + return a +} + +// ValidatorsToMinimalValidators converts array of validators to minimal validators +func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) { + for _, val := range vals { + minVals = append(minVals, val.MinimalVal()) + } + return +} diff --git a/contracts/validatorset/contract/ValidatorSet.abi b/contracts/validatorset/contract/ValidatorSet.abi deleted file mode 100644 index 367a36292d..0000000000 --- a/contracts/validatorset/contract/ValidatorSet.abi +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[],"name":"finalizeChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parentHash","type":"bytes32"},{"indexed":false,"name":"_newSet","type":"address[]"}],"name":"InitiateChange","type":"event"}] \ No newline at end of file diff --git a/contracts/validatorset/contract/ValidatorSet.bin b/contracts/validatorset/contract/ValidatorSet.bin deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contracts/validatorset/contract/ValidatorSet.sol b/contracts/validatorset/contract/ValidatorSet.sol deleted file mode 100644 index df23c1d369..0000000000 --- a/contracts/validatorset/contract/ValidatorSet.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity 0.5.9; - -interface ValidatorSet { - /// Get initial validator set - function getInitialValidators() - external - view - returns (address[] memory, uint256[] memory); - - /// Get current validator set (last enacted or initial if no changes ever made) with current stake. - function getValidators() - external - view - returns (address[] memory, uint256[] memory); -} \ No newline at end of file diff --git a/contracts/validatorset/validatorset.go b/contracts/validatorset/validatorset.go deleted file mode 100644 index c64bf8614c..0000000000 --- a/contracts/validatorset/validatorset.go +++ /dev/null @@ -1,399 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package validatorset - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// ValidatorsetABI is the input ABI used to generate the binding from. -const ValidatorsetABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"finalizeChange\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getValidators\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"},{\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"reportMalicious\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"reportBenign\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_parentHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"_newSet\",\"type\":\"address[]\"}],\"name\":\"InitiateChange\",\"type\":\"event\"}]" - -// Validatorset is an auto generated Go binding around an Ethereum contract. -type Validatorset struct { - ValidatorsetCaller // Read-only binding to the contract - ValidatorsetTransactor // Write-only binding to the contract - ValidatorsetFilterer // Log filterer for contract events -} - -// ValidatorsetCaller is an auto generated read-only Go binding around an Ethereum contract. -type ValidatorsetCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ValidatorsetTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ValidatorsetFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ValidatorsetSession struct { - Contract *Validatorset // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ValidatorsetCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ValidatorsetCallerSession struct { - Contract *ValidatorsetCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ValidatorsetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ValidatorsetTransactorSession struct { - Contract *ValidatorsetTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ValidatorsetRaw is an auto generated low-level Go binding around an Ethereum contract. -type ValidatorsetRaw struct { - Contract *Validatorset // Generic contract binding to access the raw methods on -} - -// ValidatorsetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ValidatorsetCallerRaw struct { - Contract *ValidatorsetCaller // Generic read-only contract binding to access the raw methods on -} - -// ValidatorsetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ValidatorsetTransactorRaw struct { - Contract *ValidatorsetTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewValidatorset creates a new instance of Validatorset, bound to a specific deployed contract. -func NewValidatorset(address common.Address, backend bind.ContractBackend) (*Validatorset, error) { - contract, err := bindValidatorset(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Validatorset{ValidatorsetCaller: ValidatorsetCaller{contract: contract}, ValidatorsetTransactor: ValidatorsetTransactor{contract: contract}, ValidatorsetFilterer: ValidatorsetFilterer{contract: contract}}, nil -} - -// NewValidatorsetCaller creates a new read-only instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetCaller(address common.Address, caller bind.ContractCaller) (*ValidatorsetCaller, error) { - contract, err := bindValidatorset(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ValidatorsetCaller{contract: contract}, nil -} - -// NewValidatorsetTransactor creates a new write-only instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetTransactor(address common.Address, transactor bind.ContractTransactor) (*ValidatorsetTransactor, error) { - contract, err := bindValidatorset(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ValidatorsetTransactor{contract: contract}, nil -} - -// NewValidatorsetFilterer creates a new log filterer instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetFilterer(address common.Address, filterer bind.ContractFilterer) (*ValidatorsetFilterer, error) { - contract, err := bindValidatorset(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ValidatorsetFilterer{contract: contract}, nil -} - -// bindValidatorset binds a generic wrapper to an already deployed contract. -func bindValidatorset(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ValidatorsetABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Validatorset *ValidatorsetRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Validatorset.Contract.ValidatorsetCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Validatorset *ValidatorsetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.Contract.ValidatorsetTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Validatorset *ValidatorsetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Validatorset.Contract.ValidatorsetTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Validatorset *ValidatorsetCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Validatorset.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Validatorset *ValidatorsetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Validatorset *ValidatorsetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Validatorset.Contract.contract.Transact(opts, method, params...) -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetCaller) GetValidators(opts *bind.CallOpts) ([]common.Address, []*big.Int, error) { - var ( - ret0 = new([]common.Address) - ret1 = new([]*big.Int) - ) - out := &[]interface{}{ - ret0, - ret1, - } - err := _Validatorset.contract.Call(opts, out, "getValidators") - return *ret0, *ret1, err -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetSession) GetValidators() ([]common.Address, []*big.Int, error) { - return _Validatorset.Contract.GetValidators(&_Validatorset.CallOpts) -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetCallerSession) GetValidators() ([]common.Address, []*big.Int, error) { - return _Validatorset.Contract.GetValidators(&_Validatorset.CallOpts) -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetTransactor) FinalizeChange(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "finalizeChange") -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetSession) FinalizeChange() (*types.Transaction, error) { - return _Validatorset.Contract.FinalizeChange(&_Validatorset.TransactOpts) -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetTransactorSession) FinalizeChange() (*types.Transaction, error) { - return _Validatorset.Contract.FinalizeChange(&_Validatorset.TransactOpts) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetTransactor) ReportBenign(opts *bind.TransactOpts, validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "reportBenign", validator, blockNumber) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetSession) ReportBenign(validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.Contract.ReportBenign(&_Validatorset.TransactOpts, validator, blockNumber) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetTransactorSession) ReportBenign(validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.Contract.ReportBenign(&_Validatorset.TransactOpts, validator, blockNumber) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetTransactor) ReportMalicious(opts *bind.TransactOpts, validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "reportMalicious", validator, blockNumber, proof) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetSession) ReportMalicious(validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.Contract.ReportMalicious(&_Validatorset.TransactOpts, validator, blockNumber, proof) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetTransactorSession) ReportMalicious(validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.Contract.ReportMalicious(&_Validatorset.TransactOpts, validator, blockNumber, proof) -} - -// ValidatorsetInitiateChangeIterator is returned from FilterInitiateChange and is used to iterate over the raw logs and unpacked data for InitiateChange events raised by the Validatorset contract. -type ValidatorsetInitiateChangeIterator struct { - Event *ValidatorsetInitiateChange // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ValidatorsetInitiateChangeIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ValidatorsetInitiateChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ValidatorsetInitiateChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ValidatorsetInitiateChangeIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ValidatorsetInitiateChangeIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ValidatorsetInitiateChange represents a InitiateChange event raised by the Validatorset contract. -type ValidatorsetInitiateChange struct { - ParentHash [32]byte - NewSet []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitiateChange is a free log retrieval operation binding the contract event 0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89. -// -// Solidity: event InitiateChange(bytes32 indexed _parentHash, address[] _newSet) -func (_Validatorset *ValidatorsetFilterer) FilterInitiateChange(opts *bind.FilterOpts, _parentHash [][32]byte) (*ValidatorsetInitiateChangeIterator, error) { - - var _parentHashRule []interface{} - for _, _parentHashItem := range _parentHash { - _parentHashRule = append(_parentHashRule, _parentHashItem) - } - - logs, sub, err := _Validatorset.contract.FilterLogs(opts, "InitiateChange", _parentHashRule) - if err != nil { - return nil, err - } - return &ValidatorsetInitiateChangeIterator{contract: _Validatorset.contract, event: "InitiateChange", logs: logs, sub: sub}, nil -} - -// WatchInitiateChange is a free log subscription operation binding the contract event 0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89. -// -// Solidity: event InitiateChange(bytes32 indexed _parentHash, address[] _newSet) -func (_Validatorset *ValidatorsetFilterer) WatchInitiateChange(opts *bind.WatchOpts, sink chan<- *ValidatorsetInitiateChange, _parentHash [][32]byte) (event.Subscription, error) { - - var _parentHashRule []interface{} - for _, _parentHashItem := range _parentHash { - _parentHashRule = append(_parentHashRule, _parentHashItem) - } - - logs, sub, err := _Validatorset.contract.WatchLogs(opts, "InitiateChange", _parentHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ValidatorsetInitiateChange) - if err := _Validatorset.contract.UnpackLog(event, "InitiateChange", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/eth/backend.go b/eth/backend.go index fe369b606b..87fc8b9dd0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -257,7 +257,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo // If Matic Bor is requested, set it up if chainConfig.Bor != nil { - return bor.New(chainConfig.Bor, db, ee) + return bor.New(chainConfig, db, ee) } // Otherwise assume proof-of-work diff --git a/params/config.go b/params/config.go index 7853e2e762..611b2052d6 100644 --- a/params/config.go +++ b/params/config.go @@ -316,10 +316,12 @@ func (c *CliqueConfig) String() string { // BorConfig is the consensus engine configs for Matic bor based sealing. 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 - ValidatorContract string `json:"validatorContract"` // Validator set contract + 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 + ValidatorContract string `json:"validatorContract"` // Validator set contract + StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract + Heimdall string `json:"heimdall"` // heimdall light client url } // String implements the stringer interface, returning the consensus engine details.