From 29413d48731aa700ecab92d33a388a459b4e5c9e Mon Sep 17 00:00:00 2001 From: Arijit Das Date: Mon, 7 Jun 2021 23:45:20 +0530 Subject: [PATCH] fix(dot/core): Add only extrinsic during chain reorg. (#1609) --- dot/core/messages.go | 3 +- dot/core/service.go | 33 ++++++-- dot/core/service_test.go | 49 +++++++++++ dot/sync/message_test.go | 8 +- dot/sync/syncer_test.go | 171 +++++---------------------------------- dot/sync/test_helpers.go | 165 +++++++++++++++++++++++++++++++++++++ dot/types/extrinsic.go | 24 ++++++ lib/babe/build.go | 5 +- lib/babe/build_test.go | 2 +- 9 files changed, 294 insertions(+), 166 deletions(-) diff --git a/dot/core/messages.go b/dot/core/messages.go index cda8fa8533..8b65d31790 100644 --- a/dot/core/messages.go +++ b/dot/core/messages.go @@ -35,7 +35,8 @@ func (s *Service) HandleTransactionMessage(msg *network.TransactionMessage) erro for _, tx := range txs { // validate each transaction - val, err := s.rt.ValidateTransaction(append([]byte{byte(types.TxnExternal)}, tx...)) + externalExt := types.Extrinsic(append([]byte{byte(types.TxnExternal)}, tx...)) + val, err := s.rt.ValidateTransaction(externalExt) if err != nil { logger.Error("failed to validate transaction", "err", err) return err diff --git a/dot/core/service.go b/dot/core/service.go index c7bce45155..747944587f 100644 --- a/dot/core/service.go +++ b/dot/core/service.go @@ -26,9 +26,9 @@ import ( "github.com/ChainSafe/gossamer/lib/crypto" "github.com/ChainSafe/gossamer/lib/keystore" "github.com/ChainSafe/gossamer/lib/runtime" + "github.com/ChainSafe/gossamer/lib/scale" "github.com/ChainSafe/gossamer/lib/services" "github.com/ChainSafe/gossamer/lib/transaction" - log "github.com/ChainSafe/log15" ) @@ -323,6 +323,11 @@ func (s *Service) handleChainReorg(prev, curr common.Hash) error { return err } + // subchain contains the ancestor as well so we need to remove it. + if len(subchain) > 0 { + subchain = subchain[1:] + } + // for each block in the previous chain, re-add its extrinsics back into the pool for _, hash := range subchain { body, err := s.blockState.GetBlockBody(hash) @@ -340,13 +345,30 @@ func (s *Service) handleChainReorg(prev, curr common.Hash) error { for _, ext := range exts { logger.Debug("validating transaction on re-org chain", "extrinsic", ext) - txv, err := s.rt.ValidateTransaction(ext) + decExt := &types.ExtrinsicData{} + err = decExt.DecodeVersion(ext) + if err != nil { + return err + } + + // Inherent are not signed. + if !decExt.IsSigned() { + continue + } + + encExt, err := scale.Encode(ext) + if err != nil { + return err + } + + externalExt := types.Extrinsic(append([]byte{byte(types.TxnExternal)}, encExt...)) + txv, err := s.rt.ValidateTransaction(externalExt) if err != nil { - logger.Debug("failed to validate transaction", "extrinsic", ext) + logger.Debug("failed to validate transaction", "error", err, "extrinsic", ext) continue } - vtx := transaction.NewValidTransaction(ext, txv) + vtx := transaction.NewValidTransaction(encExt, txv) s.transactionState.AddToPool(vtx) } } @@ -442,7 +464,8 @@ func (s *Service) HandleSubmittedExtrinsic(ext types.Extrinsic) error { // the transaction source is External // validate the transaction - txv, err := s.rt.ValidateTransaction(append([]byte{byte(types.TxnExternal)}, ext...)) + externalExt := types.Extrinsic(append([]byte{byte(types.TxnExternal)}, ext...)) + txv, err := s.rt.ValidateTransaction(externalExt) if err != nil { return err } diff --git a/dot/core/service_test.go b/dot/core/service_test.go index b3ee59cccc..77fc2b13ec 100644 --- a/dot/core/service_test.go +++ b/dot/core/service_test.go @@ -25,6 +25,7 @@ import ( "github.com/ChainSafe/gossamer/dot/network" "github.com/ChainSafe/gossamer/dot/state" + "github.com/ChainSafe/gossamer/dot/sync" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/keystore" @@ -166,6 +167,54 @@ func TestHandleChainReorg_NoReorg(t *testing.T) { require.NoError(t, err) } +func TestHandleChainReorg_WithReorg_Trans(t *testing.T) { + s := NewTestService(t, nil) + + bs := s.blockState + + parent, err := bs.BestBlockHeader() + require.NoError(t, err) + + block1 := sync.BuildBlock(t, s.rt, parent, nil) + err = bs.AddBlock(block1) + require.NoError(t, err) + + block2 := sync.BuildBlock(t, s.rt, block1.Header, nil) + err = bs.AddBlock(block2) + require.NoError(t, err) + + block3 := sync.BuildBlock(t, s.rt, block2.Header, nil) + err = bs.AddBlock(block3) + require.NoError(t, err) + + block4 := sync.BuildBlock(t, s.rt, block3.Header, nil) + err = bs.AddBlock(block4) + require.NoError(t, err) + + block5 := sync.BuildBlock(t, s.rt, block4.Header, nil) + err = bs.AddBlock(block5) + require.NoError(t, err) + + block31 := sync.BuildBlock(t, s.rt, block2.Header, nil) + err = bs.AddBlock(block31) + require.NoError(t, err) + + nonce := uint64(1) + + // Add extrinsic to block `block31` + ext := createExtrinsics(t, s.rt, bs.GenesisHash(), nonce) + + block41 := sync.BuildBlock(t, s.rt, block31.Header, ext) + err = bs.AddBlock(block41) + require.NoError(t, err) + + err = s.handleChainReorg(block41.Header.Hash(), block5.Header.Hash()) + require.NoError(t, err) + + pending := s.transactionState.(*state.TransactionState).Pending() + require.Equal(t, 1, len(pending)) +} + func TestHandleChainReorg_WithReorg_NoTransactions(t *testing.T) { s := NewTestService(t, nil) height := 5 diff --git a/dot/sync/message_test.go b/dot/sync/message_test.go index 53b0e9a916..9ca2966c03 100644 --- a/dot/sync/message_test.go +++ b/dot/sync/message_test.go @@ -54,7 +54,7 @@ func TestMain(m *testing.M) { } func TestService_CreateBlockResponse_MaxSize(t *testing.T) { - s := newTestSyncer(t) + s := NewTestSyncer(t) addTestBlocksToState(t, int(maxResponseSize), s.blockState) start, err := variadic.NewUint64OrHash(uint64(1)) @@ -90,7 +90,7 @@ func TestService_CreateBlockResponse_MaxSize(t *testing.T) { } func TestService_CreateBlockResponse_StartHash(t *testing.T) { - s := newTestSyncer(t) + s := NewTestSyncer(t) addTestBlocksToState(t, int(maxResponseSize), s.blockState) startHash, err := s.blockState.GetHashByNumber(big.NewInt(1)) @@ -115,7 +115,7 @@ func TestService_CreateBlockResponse_StartHash(t *testing.T) { } func TestService_CreateBlockResponse_Ascending(t *testing.T) { - s := newTestSyncer(t) + s := NewTestSyncer(t) addTestBlocksToState(t, int(maxResponseSize), s.blockState) startHash, err := s.blockState.GetHashByNumber(big.NewInt(1)) @@ -141,7 +141,7 @@ func TestService_CreateBlockResponse_Ascending(t *testing.T) { // tests the ProcessBlockRequestMessage method func TestService_CreateBlockResponse(t *testing.T) { - s := newTestSyncer(t) + s := NewTestSyncer(t) addTestBlocksToState(t, 2, s.blockState) bestHash := s.blockState.BestBlockHash() diff --git a/dot/sync/syncer_test.go b/dot/sync/syncer_test.go index 7fae639cc8..43efa24204 100644 --- a/dot/sync/syncer_test.go +++ b/dot/sync/syncer_test.go @@ -21,117 +21,33 @@ import ( "io/ioutil" "math/big" "testing" - "time" + "github.com/ChainSafe/chaindb" "github.com/ChainSafe/gossamer/dot/network" "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/common/optional" "github.com/ChainSafe/gossamer/lib/common/variadic" - "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/runtime" - rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" - "github.com/ChainSafe/gossamer/lib/runtime/wasmer" - "github.com/ChainSafe/gossamer/lib/scale" "github.com/ChainSafe/gossamer/lib/transaction" - "github.com/ChainSafe/gossamer/lib/trie" - - "github.com/ChainSafe/chaindb" - log "github.com/ChainSafe/log15" "github.com/stretchr/testify/require" ) -type mockFinalityGadget struct{} - -func (m mockFinalityGadget) VerifyBlockJustification(_ []byte) error { - return nil -} - -func newTestGenesisWithTrieAndHeader(t *testing.T) (*genesis.Genesis, *trie.Trie, *types.Header) { - gen, err := genesis.NewGenesisFromJSONRaw("../../chain/gssmr/genesis.json") - require.NoError(t, err) - - genTrie, err := genesis.NewTrieFromGenesis(gen) - require.NoError(t, err) - - genesisHeader, err := types.NewHeader(common.NewHash([]byte{0}), genTrie.MustHash(), trie.EmptyHash, big.NewInt(0), types.Digest{}) - require.NoError(t, err) - return gen, genTrie, genesisHeader -} - -func newTestSyncer(t *testing.T) *Service { - wasmer.DefaultTestLogLvl = 3 - - cfg := &Config{} - testDatadirPath, _ := ioutil.TempDir("/tmp", "test-datadir-*") - stateSrvc := state.NewService(testDatadirPath, log.LvlInfo) - stateSrvc.UseMemDB() - - gen, genTrie, genHeader := newTestGenesisWithTrieAndHeader(t) - err := stateSrvc.Initialise(gen, genHeader, genTrie) - require.NoError(t, err) - - err = stateSrvc.Start() - require.NoError(t, err) - - if cfg.BlockState == nil { - cfg.BlockState = stateSrvc.Block - } - - if cfg.StorageState == nil { - cfg.StorageState = stateSrvc.Storage - } - - if cfg.Runtime == nil { - // set state to genesis state - genState, err := rtstorage.NewTrieState(genTrie) //nolint - require.NoError(t, err) - - rtCfg := &wasmer.Config{} - rtCfg.Storage = genState - rtCfg.LogLvl = 3 - - instance, err := wasmer.NewRuntimeFromGenesis(gen, rtCfg) //nolint - require.NoError(t, err) - cfg.Runtime = instance - } - - if cfg.TransactionState == nil { - cfg.TransactionState = stateSrvc.Transaction - } - - if cfg.Verifier == nil { - cfg.Verifier = &mockVerifier{} - } - - if cfg.LogLvl == 0 { - cfg.LogLvl = log.LvlDebug - } - - if cfg.FinalityGadget == nil { - cfg.FinalityGadget = &mockFinalityGadget{} - } - - syncer, err := NewService(cfg) - require.NoError(t, err) - return syncer -} - func TestHandleBlockResponse(t *testing.T) { if testing.Short() { t.Skip() // this test takes around 4min to run } - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) syncer.highestSeenBlock = big.NewInt(132) - responder := newTestSyncer(t) + responder := NewTestSyncer(t) parent, err := responder.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) for i := 0; i < 130; i++ { - block := buildBlock(t, responder.runtime, parent) + block := BuildBlock(t, responder.runtime, parent, nil) err = responder.blockState.AddBlock(block) require.NoError(t, err) parent = block.Header @@ -161,26 +77,26 @@ func TestHandleBlockResponse(t *testing.T) { } func TestHandleBlockResponse_MissingBlocks(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) syncer.highestSeenBlock = big.NewInt(20) parent, err := syncer.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) for i := 0; i < 4; i++ { - block := buildBlock(t, syncer.runtime, parent) + block := BuildBlock(t, syncer.runtime, parent, nil) err = syncer.blockState.AddBlock(block) require.NoError(t, err) parent = block.Header } - responder := newTestSyncer(t) + responder := NewTestSyncer(t) parent, err = responder.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) for i := 0; i < 16; i++ { - block := buildBlock(t, responder.runtime, parent) + block := BuildBlock(t, responder.runtime, parent, nil) err = responder.blockState.AddBlock(block) require.NoError(t, err) parent = block.Header @@ -206,7 +122,7 @@ func TestHandleBlockResponse_MissingBlocks(t *testing.T) { } func TestRemoveIncludedExtrinsics(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) ext := []byte("nootwashere") tx := &transaction.ValidTransaction{ @@ -236,17 +152,17 @@ func TestRemoveIncludedExtrinsics(t *testing.T) { } func TestHandleBlockResponse_NoBlockData(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) _, err := syncer.ProcessBlockData(nil) require.Equal(t, ErrNilBlockData, err) } func TestHandleBlockResponse_BlockData(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) parent, err := syncer.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) - block := buildBlock(t, syncer.runtime, parent) + block := BuildBlock(t, syncer.runtime, parent, nil) bd := []*types.BlockData{{ Hash: block.Header.Hash(), @@ -264,63 +180,12 @@ func TestHandleBlockResponse_BlockData(t *testing.T) { require.Nil(t, err) } -func buildBlock(t *testing.T, instance runtime.Instance, parent *types.Header) *types.Block { - header := &types.Header{ - ParentHash: parent.Hash(), - Number: big.NewInt(0).Add(parent.Number, big.NewInt(1)), - Digest: types.Digest{}, - } - - err := instance.InitializeBlock(header) - require.NoError(t, err) - - idata := types.NewInherentsData() - err = idata.SetInt64Inherent(types.Timstap0, uint64(time.Now().Unix())) - require.NoError(t, err) - - err = idata.SetInt64Inherent(types.Babeslot, 1) - require.NoError(t, err) - - err = idata.SetBigIntInherent(types.Finalnum, big.NewInt(0)) - require.NoError(t, err) - - ienc, err := idata.Encode() - require.NoError(t, err) - - // Call BlockBuilder_inherent_extrinsics which returns the inherents as extrinsics - inherentExts, err := instance.InherentExtrinsics(ienc) - require.NoError(t, err) - - // decode inherent extrinsics - exts, err := scale.Decode(inherentExts, [][]byte{}) - require.NoError(t, err) - - // apply each inherent extrinsic - for _, ext := range exts.([][]byte) { - in, err := scale.Encode(ext) //nolint - require.NoError(t, err) - - ret, err := instance.ApplyExtrinsic(in) - require.NoError(t, err) - require.Equal(t, ret, []byte{0, 0}) - } - - res, err := instance.FinalizeBlock() - require.NoError(t, err) - res.Number = header.Number - - return &types.Block{ - Header: res, - Body: types.NewBody(inherentExts), - } -} - func TestSyncer_ExecuteBlock(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) parent, err := syncer.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) - block := buildBlock(t, syncer.runtime, parent) + block := BuildBlock(t, syncer.runtime, parent, nil) // reset parentState parentState, err := syncer.storageState.TrieState(&parent.StateRoot) @@ -332,7 +197,7 @@ func TestSyncer_ExecuteBlock(t *testing.T) { } func TestSyncer_HandleRuntimeChanges(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) _, err := runtime.GetRuntimeBlob(runtime.POLKADOT_RUNTIME_FP, runtime.POLKADOT_RUNTIME_URL) require.NoError(t, err) @@ -349,7 +214,7 @@ func TestSyncer_HandleRuntimeChanges(t *testing.T) { } func TestSyncer_HandleJustification(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) header := &types.Header{ Number: big.NewInt(1), @@ -365,11 +230,11 @@ func TestSyncer_HandleJustification(t *testing.T) { } func TestSyncer_ProcessJustification(t *testing.T) { - syncer := newTestSyncer(t) + syncer := NewTestSyncer(t) parent, err := syncer.blockState.(*state.BlockState).BestBlockHeader() require.NoError(t, err) - block := buildBlock(t, syncer.runtime, parent) + block := BuildBlock(t, syncer.runtime, parent, nil) err = syncer.blockState.(*state.BlockState).AddBlock(block) require.NoError(t, err) diff --git a/dot/sync/test_helpers.go b/dot/sync/test_helpers.go index cc9bbab10d..d0afbf3cdf 100644 --- a/dot/sync/test_helpers.go +++ b/dot/sync/test_helpers.go @@ -17,8 +17,24 @@ package sync import ( + "io/ioutil" + "math/big" + "testing" + "time" + + "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/lib/babe" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/runtime" + rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" + "github.com/ChainSafe/gossamer/lib/runtime/wasmer" + "github.com/ChainSafe/gossamer/lib/scale" + "github.com/ChainSafe/gossamer/lib/transaction" + "github.com/ChainSafe/gossamer/lib/trie" + log "github.com/ChainSafe/log15" + "github.com/stretchr/testify/require" ) // mockVerifier implements the Verifier interface @@ -51,3 +67,152 @@ func (bp *mockBlockProducer) Resume() error { } func (bp *mockBlockProducer) SetRuntime(_ runtime.Instance) {} + +type mockFinalityGadget struct{} + +func (m mockFinalityGadget) VerifyBlockJustification(_ []byte) error { + return nil +} + +// NewTestSyncer ... +func NewTestSyncer(t *testing.T) *Service { + wasmer.DefaultTestLogLvl = 3 + + cfg := &Config{} + testDatadirPath, _ := ioutil.TempDir("/tmp", "test-datadir-*") + stateSrvc := state.NewService(testDatadirPath, log.LvlInfo) + stateSrvc.UseMemDB() + + gen, genTrie, genHeader := newTestGenesisWithTrieAndHeader(t) + err := stateSrvc.Initialise(gen, genHeader, genTrie) + require.NoError(t, err) + + err = stateSrvc.Start() + require.NoError(t, err) + + if cfg.BlockState == nil { + cfg.BlockState = stateSrvc.Block + } + + if cfg.StorageState == nil { + cfg.StorageState = stateSrvc.Storage + } + + if cfg.Runtime == nil { + // set state to genesis state + genState, err := rtstorage.NewTrieState(genTrie) //nolint + require.NoError(t, err) + + rtCfg := &wasmer.Config{} + rtCfg.Storage = genState + rtCfg.LogLvl = 3 + + instance, err := wasmer.NewRuntimeFromGenesis(gen, rtCfg) //nolint + require.NoError(t, err) + cfg.Runtime = instance + } + + if cfg.TransactionState == nil { + cfg.TransactionState = stateSrvc.Transaction + } + + if cfg.Verifier == nil { + cfg.Verifier = &mockVerifier{} + } + + if cfg.LogLvl == 0 { + cfg.LogLvl = log.LvlDebug + } + + if cfg.FinalityGadget == nil { + cfg.FinalityGadget = &mockFinalityGadget{} + } + + syncer, err := NewService(cfg) + require.NoError(t, err) + return syncer +} + +func newTestGenesisWithTrieAndHeader(t *testing.T) (*genesis.Genesis, *trie.Trie, *types.Header) { + gen, err := genesis.NewGenesisFromJSONRaw("../../chain/gssmr/genesis.json") + require.NoError(t, err) + + genTrie, err := genesis.NewTrieFromGenesis(gen) + require.NoError(t, err) + + genesisHeader, err := types.NewHeader(common.NewHash([]byte{0}), genTrie.MustHash(), trie.EmptyHash, big.NewInt(0), types.Digest{}) + require.NoError(t, err) + return gen, genTrie, genesisHeader +} + +// BuildBlock ... +func BuildBlock(t *testing.T, instance runtime.Instance, parent *types.Header, ext types.Extrinsic) *types.Block { + header := &types.Header{ + ParentHash: parent.Hash(), + Number: big.NewInt(0).Add(parent.Number, big.NewInt(1)), + Digest: types.Digest{}, + } + + err := instance.InitializeBlock(header) + require.NoError(t, err) + + idata := types.NewInherentsData() + err = idata.SetInt64Inherent(types.Timstap0, uint64(time.Now().Unix())) + require.NoError(t, err) + + err = idata.SetInt64Inherent(types.Babeslot, 1) + require.NoError(t, err) + + err = idata.SetBigIntInherent(types.Finalnum, big.NewInt(0)) + require.NoError(t, err) + + ienc, err := idata.Encode() + require.NoError(t, err) + + // Call BlockBuilder_inherent_extrinsics which returns the inherents as extrinsics + inherentExts, err := instance.InherentExtrinsics(ienc) + require.NoError(t, err) + + // decode inherent extrinsics + exts, err := scale.Decode(inherentExts, [][]byte{}) + require.NoError(t, err) + + inExt := exts.([][]byte) + + var body *types.Body + if ext != nil { + var txn *transaction.Validity + externalExt := types.Extrinsic(append([]byte{byte(types.TxnExternal)}, ext...)) + txn, err = instance.ValidateTransaction(externalExt) + require.NoError(t, err) + + vtx := transaction.NewValidTransaction(ext, txn) + _, err = instance.ApplyExtrinsic(ext) // TODO: Determine error for ret + require.NoError(t, err) + + body, err = babe.ExtrinsicsToBody(inExt, []*transaction.ValidTransaction{vtx}) + require.NoError(t, err) + + } else { + body = types.NewBody(inherentExts) + } + + // apply each inherent extrinsic + for _, ext := range inExt { + in, err := scale.Encode(ext) //nolint + require.NoError(t, err) + + ret, err := instance.ApplyExtrinsic(in) + require.NoError(t, err) + require.Equal(t, ret, []byte{0, 0}) + } + + res, err := instance.FinalizeBlock() + require.NoError(t, err) + res.Number = header.Number + + return &types.Block{ + Header: res, + Body: body, + } +} diff --git a/dot/types/extrinsic.go b/dot/types/extrinsic.go index 2ff3047ed8..e1e02deba7 100644 --- a/dot/types/extrinsic.go +++ b/dot/types/extrinsic.go @@ -17,17 +17,41 @@ package types import ( + "bytes" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/centrifuge/go-substrate-rpc-client/v2/scale" + ctypes "github.com/centrifuge/go-substrate-rpc-client/v2/types" ) // Extrinsic is a generic transaction whose format is verified in the runtime type Extrinsic []byte +// ExtrinsicData is a transaction which embeds the `ctypes.Extrinsic` and has additional functionality. +type ExtrinsicData struct { + ctypes.Extrinsic +} + // NewExtrinsic creates a new Extrinsic given a byte slice func NewExtrinsic(e []byte) Extrinsic { return Extrinsic(e) } +// DecodeVersion decodes only the version field of the Extrinsic. +func (e *ExtrinsicData) DecodeVersion(encExt Extrinsic) error { + decoder := scale.NewDecoder(bytes.NewReader(encExt)) + _, err := decoder.DecodeUintCompact() + if err != nil { + return err + } + + err = decoder.Decode(&e.Version) + if err != nil { + return err + } + return nil +} + // Hash returns the blake2b hash of the extrinsic func (e Extrinsic) Hash() common.Hash { hash, err := common.Blake2bHash(e) diff --git a/lib/babe/build.go b/lib/babe/build.go index ea3e1e2785..367f11c038 100644 --- a/lib/babe/build.go +++ b/lib/babe/build.go @@ -151,7 +151,7 @@ func (b *BlockBuilder) buildBlock(parent *types.Header, slot Slot) (*types.Block logger.Trace("built block seal") - body, err := extrinsicsToBody(inherents, included) + body, err := ExtrinsicsToBody(inherents, included) if err != nil { return nil, err } @@ -344,7 +344,8 @@ func hasSlotEnded(slot Slot) bool { return time.Since(slotEnd) >= 0 } -func extrinsicsToBody(inherents [][]byte, txs []*transaction.ValidTransaction) (*types.Body, error) { +// ExtrinsicsToBody returns scale encoded block body which contains inherent and extrinsic. +func ExtrinsicsToBody(inherents [][]byte, txs []*transaction.ValidTransaction) (*types.Body, error) { extrinsics := types.BytesArrayToExtrinsics(inherents) for _, tx := range txs { diff --git a/lib/babe/build_test.go b/lib/babe/build_test.go index 5da12b3cf4..e84dc8943c 100644 --- a/lib/babe/build_test.go +++ b/lib/babe/build_test.go @@ -345,7 +345,7 @@ func TestDecodeExtrinsicBody(t *testing.T) { vtx := transaction.NewValidTransaction(ext, &transaction.Validity{}) - body, err := extrinsicsToBody(inh, []*transaction.ValidTransaction{vtx}) + body, err := ExtrinsicsToBody(inh, []*transaction.ValidTransaction{vtx}) require.Nil(t, err) require.NotNil(t, body)