diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 60569caec5e66d6fe0d6d4a9d8b7873cbe0d7ddd..da739abd7b019ed0f072c06546528236524f9e97 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/bor.go b/consensus/bor/bor.go index 2c2fcf020fcd46ed38a1b13487853419962c2a43..6daaebf8e84a2d1dd84754758df144e7053811db 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -13,14 +13,17 @@ import ( "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 +36,7 @@ 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":false,"inputs":[],"name":"proposeSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newSpan","type":"uint256"},{"name":"proposer","type":"address"},{"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":"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 ( checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database @@ -56,6 +59,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 @@ -227,8 +231,9 @@ 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 @@ -247,11 +252,17 @@ type Bor struct { } // 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 @@ -259,7 +270,8 @@ func New(config *params.BorConfig, db ethdb.Database, ethAPI *ethapi.PublicBlock signatures, _ := lru.NewARC(inmemorySignatures) vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) c := &Bor{ - config: &conf, + chainConfig: chainConfig, + config: borConfig, db: db, ethAPI: ethAPI, recents: recents, @@ -267,6 +279,7 @@ func New(config *params.BorConfig, db ethdb.Database, ethAPI *ethapi.PublicBlock proposals: make(map[common.Address]bool), validatorSetABI: vABI, } + return c } @@ -646,6 +659,9 @@ 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 + // c.commitSpan(state, header, chainContext{Chain: chain, Bor: c}) + // 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 +670,9 @@ 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 + // c.commitSpan(state, header, chainContext{Chain: chain, Bor: c}) + // 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) @@ -792,21 +811,13 @@ func (c *Bor) Close() error { // 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) -} - -// GetValidators get current validators -func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, validatorContract string, ethAPI *ethapi.PublicBlockChainAPI) ([]*Validator, error) { // block blockNr := rpc.BlockNumber(snapshotNumber) - // validator set ABI - validatorSetABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) - // 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 +828,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 +849,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 +864,107 @@ func GetValidators(snapshotNumber uint64, blockNumber uint64, sprint uint64, val return valz, nil } +func (c *Bor) commitSpan( + state *state.StateDB, + header *types.Header, + chain core.ChainContext, +) error { + // method + method := "commitSpan" + + // get packed data + data, err := c.validatorSetABI.Pack(method) + 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) +} + +// +// 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/eth/backend.go b/eth/backend.go index fe369b606b15df2e7f38e488e33eeef8caeaeeee..87fc8b9dd0b2a3c5a6c40d7767e62d0d9ec3231c 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 7853e2e762ca618112c15b03ff066a9dc8bf96f1..202dc7a1e1f354c2df359b48077038240da584a3 100644 --- a/params/config.go +++ b/params/config.go @@ -320,6 +320,7 @@ type BorConfig struct { 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 + Heimdall string `json:"heimdall"` // heimdall light client url } // String implements the stringer interface, returning the consensus engine details.