diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 127a396854c8c1b839a8764c59b65ef4a5f9b516..d84288d42900efdc1982c193d6ccfdab9d5702c4 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -563,7 +563,6 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare if err != nil { return err } - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { return errUnauthorizedSigner } @@ -1006,9 +1005,11 @@ func (c *Bor) checkAndCommitSpan( for i := 0; i < 2; i++ { err = <-errors if err != nil { + close(errors) 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) { @@ -1231,19 +1232,20 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) { func (c *Bor) IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool { header := chain.CurrentHeader() - snap, err := c.snapshot(chain, header.Number.Uint64(), header.Hash(), nil) + 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 snap.ValidatorSet.Validators { + 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)) } @@ -1337,7 +1339,7 @@ func applyMessage( if err != nil { state.Finalise(true) } - + return nil } diff --git a/consensus/bor_test/bor_test.go b/consensus/bor_test/bor_test.go index afb88ca54c9bfead468c4f5645f20b97e9bb40a6..88eb9245b556683db89abbcaef82abb6e21204ec 100644 --- a/consensus/bor_test/bor_test.go +++ b/consensus/bor_test/bor_test.go @@ -7,12 +7,13 @@ import ( "math/big" "testing" - "github.com/stretchr/testify/assert" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus/bor" "github.com/maticnetwork/bor/core" "github.com/maticnetwork/bor/core/rawdb" + "github.com/maticnetwork/bor/core/state" "github.com/maticnetwork/bor/crypto/secp256k1" + "github.com/stretchr/testify/assert" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/crypto" @@ -23,8 +24,11 @@ import ( "github.com/maticnetwork/bor/node" ) -const ( +var ( 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 ) type initializeData struct { @@ -39,48 +43,25 @@ func TestCommitSpan(t *testing.T) { _bor := engine.(*bor.Bor) // Mock HeimdallClient.FetchWithRetry to return span data from span.json - spanData, err := ioutil.ReadFile("span.json") - if err != nil { - t.Fatalf("%s", err) - } - res := &bor.ResponseWithHeight{} - if err := json.Unmarshal(spanData, res); err != nil { - t.Fatalf("%s", err) - } + res, heimdallSpan := loadSpanFromFile(t) h := &mocks.IHeimdallClient{} - h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil) + h.On("FetchWithRetry", "bor", "span", "1"). + Return(res, nil). + Times(2) // both FinalizeAndAssemble and chain.InsertChain call HeimdallClient.FetchWithRetry. @todo Investigate this in depth _bor.SetHeimdallClient(h) - // Build 1st blocks header db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) - header := block.Header() // get 0th block header and mutate it as required - header.Number = big.NewInt(1) - header.ParentHash = block.Hash() - header.Time += (init.genesis.Config.Bor.Period + 1) - header.Extra = make([]byte, 97) // vanity (32) + extraSeal (65) - privKey, _ := hex.DecodeString("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + // Build 1st block's header + header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) statedb, err := chain.State() if err != nil { t.Fatalf("%s", err) } - block, err = _bor.FinalizeAndAssemble(chain, header, statedb, nil, nil, nil) - if err != nil { - t.Fatalf("%s", err) - } - - sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), privKey) - 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 { - t.Fatalf("%s", err) - } + _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 @@ -88,10 +69,7 @@ func TestCommitSpan(t *testing.T) { t.Fatalf("%s", err) } - var heimdallSpan bor.HeimdallSpan - if err := json.Unmarshal(res.Result, &heimdallSpan); err != nil { - t.Fatalf("%s", err) - } + assert.Equal(t, len(validators), 3) 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) @@ -99,35 +77,78 @@ func TestCommitSpan(t *testing.T) { } func TestIsValidatorAction(t *testing.T) { - var ( - db = rawdb.NewMemoryDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - addr = crypto.PubkeyToAddress(key.PublicKey) - ) - init := buildEthereumInstance(t, db) - ethereum := init.ethereum - chain := ethereum.BlockChain() - engine := ethereum.Engine() - - // proposeState - data, _ := hex.DecodeString("ede01f170000000000000000000000000000000000000000000000000000000000000000") - tx := types.NewTransaction( + 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), - data, + proposeStateData, ) - assert.True(t, engine.(*bor.Bor).IsValidatorAction(chain, addr, tx)) + assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) - // proposeSpan - data, _ = hex.DecodeString("4b0e4d17") tx = types.NewTransaction( 0, common.HexToAddress(chain.Config().Bor.ValidatorContract), big.NewInt(0), 0, big.NewInt(0), - data, + proposeSpanData, ) - assert.True(t, engine.(*bor.Bor).IsValidatorAction(chain, addr, tx)) + assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) + + res, heimdallSpan := loadSpanFromFile(t) + h := &mocks.IHeimdallClient{} + h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil) + _bor.SetHeimdallClient(h) + + // Build 1st block's header + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + + header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) + statedb, err := chain.State() + if err != nil { + t.Fatalf("%s", err) + } + + _key, _ := hex.DecodeString(privKey) + insertNewBlock(t, _bor, chain, header, statedb, _key) + block = types.NewBlockWithHeader(header) + + 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) + } + + 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 buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { @@ -139,7 +160,6 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { if err := json.Unmarshal(genesisData, gen); err != nil { t.Fatalf("%s", err) } - // chainConfig, _, err := core.SetupGenesisBlock(db, gen) ethConf := ð.Config{ Genesis: gen, } @@ -181,3 +201,53 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { ethereum: ethereum, } } + +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 { + t.Fatalf("%s", err) + } + + sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), privKey) + 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 { + t.Fatalf("%s", err) + } +} + +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) + if err != nil { + t.Fatalf("%s", err) + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + return header +} + +func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) { + spanData, err := ioutil.ReadFile("span.json") + if err != nil { + t.Fatalf("%s", err) + } + res := &bor.ResponseWithHeight{} + if err := json.Unmarshal(spanData, res); err != nil { + t.Fatalf("%s", err) + } + + heimdallSpan := &bor.HeimdallSpan{} + if err := json.Unmarshal(res.Result, heimdallSpan); err != nil { + t.Fatalf("%s", err) + } + return res, heimdallSpan +}