Skip to content

Commit 1551e66

Browse files
authored
fix(core): fix txn pool for latest runtime (#2809)
Fix transaction formatting, fix txnPool, and redo core service orchestrations for service tests
1 parent 57168fc commit 1551e66

16 files changed

+539
-230
lines changed

dot/core/errors.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ import (
88
)
99

1010
var (
11-
12-
// ErrServiceStopped is returned when the service has been stopped
13-
ErrServiceStopped = errors.New("service has been stopped")
14-
15-
// ErrInvalidBlock is returned when a block cannot be verified
16-
ErrInvalidBlock = errors.New("could not verify block")
17-
1811
ErrNilRuntime = errors.New("cannot have nil runtime")
1912

2013
ErrNilBlockHandlerParameter = errors.New("unable to handle block due to nil parameter")
2114

2215
// ErrEmptyRuntimeCode is returned when the storage :code is empty
2316
ErrEmptyRuntimeCode = errors.New("new :code is empty")
17+
18+
errInvalidTransactionQueueVersion = errors.New("invalid transaction queue version")
2419
)

dot/core/helpers_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
package core
55

66
import (
7+
"bytes"
78
"path/filepath"
89
"testing"
910

11+
"github.com/ChainSafe/gossamer/dot/network"
1012
"github.com/ChainSafe/gossamer/dot/state"
1113
"github.com/ChainSafe/gossamer/dot/types"
1214
"github.com/ChainSafe/gossamer/internal/log"
@@ -19,10 +21,133 @@ import (
1921
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
2022
"github.com/ChainSafe/gossamer/lib/trie"
2123
"github.com/ChainSafe/gossamer/lib/utils"
24+
"github.com/ChainSafe/gossamer/pkg/scale"
2225
"github.com/golang/mock/gomock"
2326
"github.com/stretchr/testify/require"
2427
)
2528

29+
func balanceKey(t *testing.T, pub []byte) (bKey []byte) {
30+
t.Helper()
31+
32+
h0, err := common.Twox128Hash([]byte("System"))
33+
require.NoError(t, err)
34+
h1, err := common.Twox128Hash([]byte("Account"))
35+
require.NoError(t, err)
36+
h2, err := common.Blake2b128(pub)
37+
require.NoError(t, err)
38+
return bytes.Join([][]byte{h0, h1, h2, pub}, nil)
39+
}
40+
41+
// Creates test service, used now for testing txnPool but can be used elsewhere when needed
42+
func createTestService(t *testing.T, genesisFilePath string,
43+
pubKey []byte, accountInfo types.AccountInfo, ctrl *gomock.Controller) (service *Service, encodedExtrinsic []byte) {
44+
t.Helper()
45+
46+
gen, err := genesis.NewGenesisFromJSONRaw(genesisFilePath)
47+
require.NoError(t, err)
48+
49+
genesisTrie, err := wasmer.NewTrieFromGenesis(*gen)
50+
require.NoError(t, err)
51+
52+
// Extrinsic and context related stuff
53+
aliceBalanceKey := balanceKey(t, pubKey)
54+
encodedAccountInfo, err := scale.Marshal(accountInfo)
55+
require.NoError(t, err)
56+
57+
genesisHeader := &types.Header{
58+
StateRoot: genesisTrie.MustHash(),
59+
Number: 0,
60+
}
61+
62+
cfgKeystore := keystore.NewGlobalKeystore()
63+
kp, err := sr25519.GenerateKeypair()
64+
require.NoError(t, err)
65+
err = cfgKeystore.Acco.Insert(kp)
66+
require.NoError(t, err)
67+
68+
// Create state service
69+
var stateSrvc *state.Service
70+
testDatadirPath := t.TempDir()
71+
72+
// Set up block and storage state
73+
telemetryMock := NewMockClient(ctrl)
74+
telemetryMock.EXPECT().SendMessage(gomock.Any()).AnyTimes()
75+
76+
stateConfig := state.Config{
77+
Path: testDatadirPath,
78+
LogLevel: log.Critical,
79+
Telemetry: telemetryMock,
80+
}
81+
82+
stateSrvc = state.NewService(stateConfig)
83+
stateSrvc.UseMemDB()
84+
85+
err = stateSrvc.Initialise(gen, genesisHeader, &genesisTrie)
86+
require.NoError(t, err)
87+
88+
// Start state service
89+
err = stateSrvc.Start()
90+
require.NoError(t, err)
91+
92+
cfgBlockState := stateSrvc.Block
93+
cfgStorageState := stateSrvc.Storage
94+
cfgCodeSubstitutedState := stateSrvc.Base
95+
96+
var rtCfg wasmer.Config
97+
rtCfg.Storage = rtstorage.NewTrieState(&genesisTrie)
98+
99+
rtCfg.CodeHash, err = cfgStorageState.LoadCodeHash(nil)
100+
require.NoError(t, err)
101+
102+
nodeStorage := runtime.NodeStorage{}
103+
nodeStorage.BaseDB = stateSrvc.Base
104+
105+
rtCfg.NodeStorage = nodeStorage
106+
107+
cfgRuntime, err := wasmer.NewRuntimeFromGenesis(rtCfg)
108+
require.NoError(t, err)
109+
110+
cfgRuntime.(*wasmer.Instance).GetContext().Storage.Set(aliceBalanceKey, encodedAccountInfo)
111+
// this key is System.UpgradedToDualRefCount -> set to true since all accounts have been upgraded to v0.9 format
112+
cfgRuntime.(*wasmer.Instance).GetContext().Storage.Set(common.UpgradedToDualRefKey, []byte{1})
113+
114+
cfgBlockState.StoreRuntime(cfgBlockState.BestBlockHash(), cfgRuntime)
115+
116+
// Hash of encrypted centrifuge extrinsic
117+
testCallArguments := []byte{0xab, 0xcd}
118+
extHex := runtime.NewTestExtrinsic(t, cfgRuntime, genesisHeader.Hash(), cfgBlockState.BestBlockHash(),
119+
0, "System.remark", testCallArguments)
120+
encodedExtrinsic = common.MustHexToBytes(extHex)
121+
122+
cfgCodeSubstitutes := make(map[common.Hash]string)
123+
124+
genesisData, err := cfgCodeSubstitutedState.LoadGenesisData()
125+
require.NoError(t, err)
126+
127+
for k, v := range genesisData.CodeSubstitutes {
128+
cfgCodeSubstitutes[common.MustHexToHash(k)] = v
129+
}
130+
131+
cfgCodeSubstitutedState = stateSrvc.Base
132+
133+
cfg := &Config{
134+
Keystore: cfgKeystore,
135+
LogLvl: log.Critical,
136+
BlockState: cfgBlockState,
137+
StorageState: cfgStorageState,
138+
TransactionState: stateSrvc.Transaction,
139+
EpochState: stateSrvc.Epoch,
140+
CodeSubstitutedState: cfgCodeSubstitutedState,
141+
Runtime: cfgRuntime,
142+
Network: new(network.Service),
143+
CodeSubstitutes: cfgCodeSubstitutes,
144+
}
145+
service, err = NewService(cfg)
146+
require.NoError(t, err)
147+
148+
return service, encodedExtrinsic
149+
}
150+
26151
// NewTestService creates a new test core service
27152
func NewTestService(t *testing.T, cfg *Config) *Service {
28153
t.Helper()

dot/core/messages.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ func (s *Service) validateTransaction(head *types.Header, rt RuntimeInstance,
2828
rt.SetContextStorage(ts)
2929

3030
// validate each transaction
31-
externalExt := types.Extrinsic(append([]byte{byte(types.TxnExternal)}, tx...))
31+
externalExt, err := s.buildExternalTransaction(rt, tx)
32+
if err != nil {
33+
return nil, fmt.Errorf("building external transaction: %w", err)
34+
}
35+
3236
validity, err = rt.ValidateTransaction(externalExt)
3337
if err != nil {
3438
logger.Debugf("failed to validate transaction: %s", err)
@@ -72,12 +76,10 @@ func (s *Service) HandleTransactionMessage(peerID peer.ID, msg *network.Transact
7276

7377
allTxnsAreValid := true
7478
for _, tx := range txs {
75-
txnIsValid := true
7679
validity, err := s.validateTransaction(head, rt, tx)
7780
if err != nil {
78-
txnIsValid = false
7981
allTxnsAreValid = false
80-
switch err := err.(type) {
82+
switch err.(type) {
8183
case runtime.InvalidTransaction:
8284
s.net.ReportPeer(peerset.ReputationChange{
8385
Value: peerset.BadTransactionValue,
@@ -87,9 +89,10 @@ func (s *Service) HandleTransactionMessage(peerID peer.ID, msg *network.Transact
8789
default:
8890
return false, fmt.Errorf("validating transaction from peerID %s: %w", peerID, err)
8991
}
92+
continue
9093
}
9194

92-
if txnIsValid && validity.Propagate {
95+
if validity.Propagate {
9396
// find tx(s) that should propagate
9497
toPropagate = append(toPropagate, tx)
9598
}

dot/core/messages_integration_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,17 @@ func TestService_HandleBlockProduced(t *testing.T) {
8888
err = digest.Add(*prd)
8989
require.NoError(t, err)
9090

91+
// Used to define the state root of new block for testing
92+
parentHash := s.blockState.GenesisHash()
93+
genesisBlock, err := s.blockState.GetBlockByHash(parentHash)
94+
require.NoError(t, err)
95+
9196
newBlock := types.Block{
9297
Header: types.Header{
9398
Number: 1,
94-
ParentHash: s.blockState.BestBlockHash(),
99+
ParentHash: parentHash,
95100
Digest: digest,
101+
StateRoot: genesisBlock.Header.StateRoot,
96102
},
97103
Body: *types.NewBody([]types.Extrinsic{}),
98104
}

dot/core/messages_test.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package core
55

66
import (
7+
"bytes"
78
"errors"
89
"testing"
910

@@ -44,8 +45,9 @@ type mockGetRuntime struct {
4445
}
4546

4647
type mockBlockState struct {
47-
bestHeader *mockBestHeader
48-
getRuntime *mockGetRuntime
48+
bestHeader *mockBestHeader
49+
getRuntime *mockGetRuntime
50+
callsBestBlockHash bool
4951
}
5052

5153
type mockStorageState struct {
@@ -252,6 +254,7 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
252254
getRuntime: &mockGetRuntime{
253255
runtime: runtimeMock2,
254256
},
257+
callsBestBlockHash: true,
255258
},
256259
mockStorageState: &mockStorageState{
257260
input: &common.Hash{},
@@ -261,8 +264,12 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
261264
runtime: runtimeMock2,
262265
setContextStorage: &mockSetContextStorage{trieState: &storage.TrieState{}},
263266
validateTxn: &mockValidateTxn{
264-
input: types.Extrinsic(append([]byte{byte(types.TxnExternal)}, testExtrinsic[0]...)),
265-
err: invalidTransaction,
267+
input: types.Extrinsic(bytes.Join([][]byte{
268+
{byte(types.TxnExternal)},
269+
testExtrinsic[0],
270+
testEmptyHeader.StateRoot.ToBytes(),
271+
}, nil)),
272+
err: invalidTransaction,
266273
},
267274
},
268275
args: args{
@@ -291,6 +298,7 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
291298
getRuntime: &mockGetRuntime{
292299
runtime: runtimeMock3,
293300
},
301+
callsBestBlockHash: true,
294302
},
295303
mockStorageState: &mockStorageState{
296304
input: &common.Hash{},
@@ -308,7 +316,11 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
308316
runtime: runtimeMock3,
309317
setContextStorage: &mockSetContextStorage{trieState: &storage.TrieState{}},
310318
validateTxn: &mockValidateTxn{
311-
input: types.Extrinsic(append([]byte{byte(types.TxnExternal)}, testExtrinsic[0]...)),
319+
input: types.Extrinsic(bytes.Join([][]byte{
320+
{byte(types.TxnExternal)},
321+
testExtrinsic[0],
322+
testEmptyHeader.StateRoot.ToBytes(),
323+
}, nil)),
312324
validity: &transaction.Validity{Propagate: true},
313325
},
314326
},
@@ -344,6 +356,9 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
344356
tt.mockBlockState.getRuntime.runtime,
345357
tt.mockBlockState.getRuntime.err)
346358
}
359+
if tt.mockBlockState.callsBestBlockHash {
360+
blockState.EXPECT().BestBlockHash().Return(common.Hash{})
361+
}
347362
s.blockState = blockState
348363
}
349364
if tt.mockStorageState != nil {
@@ -365,6 +380,19 @@ func TestServiceHandleTransactionMessage(t *testing.T) {
365380
rt.EXPECT().SetContextStorage(tt.mockRuntime.setContextStorage.trieState)
366381
rt.EXPECT().ValidateTransaction(tt.mockRuntime.validateTxn.input).
367382
Return(tt.mockRuntime.validateTxn.validity, tt.mockRuntime.validateTxn.err)
383+
rt.EXPECT().Version().Return(runtime.Version{
384+
SpecName: []byte("polkadot"),
385+
ImplName: []byte("parity-polkadot"),
386+
AuthoringVersion: authoringVersion,
387+
SpecVersion: specVersion,
388+
ImplVersion: implVersion,
389+
APIItems: []runtime.APIItem{{
390+
Name: common.MustBlake2b8([]byte("TaggedTransactionQueue")),
391+
Ver: 3,
392+
}},
393+
TransactionVersion: transactionVersion,
394+
StateVersion: stateVersion,
395+
})
368396
}
369397

370398
res, err := s.HandleTransactionMessage(tt.args.peerID, tt.args.msg)

0 commit comments

Comments
 (0)