From 55de62e2984a9e0a3db0a9a663f5133bb5928376 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 26 Jan 2023 22:25:37 +0530 Subject: [PATCH] feat(lib/babe): Submit BABE equivocation report (#2947) - Added support for runtime functions `BabeGenerateKeyOwnershipProof` and `BabeSubmitReportEquivocationUnsignedExtrinsic` - and report a babe equivocation report when it occurs Issue #2853 --- dot/core/interfaces.go | 6 + dot/core/mocks_test.go | 29 ++ dot/interfaces.go | 2 + dot/rpc/modules/interfaces_test.go | 2 + dot/state/interfaces.go | 2 + dot/sync/mock_runtime_test.go | 29 ++ dot/types/equivocation.go | 32 ++ dot/types/equivocation_test.go | 30 ++ lib/babe/errors.go | 3 + lib/babe/mocks/runtime.go | 417 +++++++++++++++++++++++++++ lib/babe/mocks_generate_test.go | 2 + lib/babe/verify.go | 46 +++ lib/babe/verify_test.go | 143 ++++++++- lib/blocktree/hashtoruntime_test.go | 16 +- lib/blocktree/interfaces.go | 2 + lib/blocktree/mocks_generate_test.go | 2 +- lib/blocktree/mocks_test.go | 203 +++++++------ lib/runtime/constants.go | 5 + lib/runtime/mocks/mocks.go | 29 ++ lib/runtime/test_helpers.go | 2 + lib/runtime/wasmer/exports.go | 50 ++++ lib/runtime/wasmer/exports_test.go | 103 ++++++- pkg/scale/decode.go | 2 +- 23 files changed, 1054 insertions(+), 103 deletions(-) create mode 100644 dot/types/equivocation.go create mode 100644 dot/types/equivocation_test.go create mode 100644 lib/babe/mocks/runtime.go diff --git a/dot/core/interfaces.go b/dot/core/interfaces.go index 7b2ed1b066..cab5168e41 100644 --- a/dot/core/interfaces.go +++ b/dot/core/interfaces.go @@ -45,6 +45,12 @@ type RuntimeInstance interface { DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) CheckInherents() + BabeGenerateKeyOwnershipProof(slot uint64, authorityID [32]byte) ( + types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic( + equivocationProof types.BabeEquivocationProof, + keyOwnershipProof types.OpaqueKeyOwnershipProof, + ) error RandomSeed() OffchainWorker() GenerateSessionKeys() diff --git a/dot/core/mocks_test.go b/dot/core/mocks_test.go index 28a34fd1f9..7be93f6e29 100644 --- a/dot/core/mocks_test.go +++ b/dot/core/mocks_test.go @@ -549,6 +549,35 @@ func (mr *MockRuntimeInstanceMockRecorder) BabeConfiguration() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeConfiguration)) } +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockRuntimeInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockRuntimeInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockRuntimeInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockRuntimeInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + // CheckInherents mocks base method. func (m *MockRuntimeInstance) CheckInherents() { m.ctrl.T.Helper() diff --git a/dot/interfaces.go b/dot/interfaces.go index 7f2b895dfd..44235afff3 100644 --- a/dot/interfaces.go +++ b/dot/interfaces.go @@ -64,6 +64,8 @@ type runtimeInterface interface { DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) CheckInherents() + BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error RandomSeed() OffchainWorker() GenerateSessionKeys() diff --git a/dot/rpc/modules/interfaces_test.go b/dot/rpc/modules/interfaces_test.go index 4916e173bb..1acdd3939d 100644 --- a/dot/rpc/modules/interfaces_test.go +++ b/dot/rpc/modules/interfaces_test.go @@ -33,6 +33,8 @@ type Runtime interface { ExecuteBlock(block *types.Block) ([]byte, error) DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) + BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error CheckInherents() RandomSeed() OffchainWorker() diff --git a/dot/state/interfaces.go b/dot/state/interfaces.go index bb0865b682..c32195e074 100644 --- a/dot/state/interfaces.go +++ b/dot/state/interfaces.go @@ -89,6 +89,8 @@ type Runtime interface { DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) CheckInherents() + BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error RandomSeed() OffchainWorker() GenerateSessionKeys() diff --git a/dot/sync/mock_runtime_test.go b/dot/sync/mock_runtime_test.go index ed15b7a273..f698777f38 100644 --- a/dot/sync/mock_runtime_test.go +++ b/dot/sync/mock_runtime_test.go @@ -68,6 +68,35 @@ func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) } +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + // CheckInherents mocks base method. func (m *MockInstance) CheckInherents() { m.ctrl.T.Helper() diff --git a/dot/types/equivocation.go b/dot/types/equivocation.go new file mode 100644 index 0000000000..d94f6495f0 --- /dev/null +++ b/dot/types/equivocation.go @@ -0,0 +1,32 @@ +// Copyright 2023 ChainSafe Systems (ON) +// SPDX-License-Identifier: LGPL-3.0-only + +package types + +import "github.com/ChainSafe/gossamer/lib/crypto/sr25519" + +// BabeEquivocationProof represents a babe equivocation proof. +// An equivocation happens when a validator produces more than one block on the same slot. +// The proof of equivocation are the given distinct headers that were signed by the validator +// and which include the slot number. +type BabeEquivocationProof struct { + // Offender is the public key of the equivocator. + Offender AuthorityID + // Slot at which the equivocation happened. + Slot uint64 + // FirstHeader is the first header involved in the equivocation. + FirstHeader Header + // SecondHeader is the second header involved in the equivocation. + SecondHeader Header +} + +// AuthorityID represents a babe authority identifier. +type AuthorityID [sr25519.PublicKeyLength]byte + +// OpaqueKeyOwnershipProof is an opaque type used to represent the key ownership proof at the +// runtime API boundary. The inner value is an encoded representation of the actual key +// ownership proof which will be parameterized when defining the runtime. At +// the runtime API boundary this type is unknown and as such we keep this +// opaque representation, implementers of the runtime API will have to make +// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. +type OpaqueKeyOwnershipProof []byte diff --git a/dot/types/equivocation_test.go b/dot/types/equivocation_test.go new file mode 100644 index 0000000000..1e227f9342 --- /dev/null +++ b/dot/types/equivocation_test.go @@ -0,0 +1,30 @@ +// Copyright 2022 ChainSafe Systems (ON) +// SPDX-License-Identifier: LGPL-3.0-only + +package types + +import ( + "testing" + + "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/stretchr/testify/require" +) + +func TestEquivocationProof(t *testing.T) { + // To get these bytes run + // https://github.com/paritytech/substrate/blob/17c07af0b953b84dbe89341294e98e586f9b4591/frame/babe/src/tests.rs#L932 + expectedEncoding := common.MustHexToBytes("0xdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa86270b0000000000000043fd935464ab466417a2d3b51b750b3047acc94708aa8e69bb01d19e7ba841f428cee631e4d752a4de8130431b63246d695dcc87af881316251bc6d35651f9508a03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140c06424142453402000000000a0000000000000004424142456902010cdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa862701000000000000003a3d45dc55b57bf542f4c6ff41af080ec675317f4ed50ae1d2713bf9f892692d010000000000000054c71c235773b82115f0744252369c13414fd0e8bad3e8feff462c6a4bb58a0f0100000000000000c6e9d02ce38de7b255382f804a64f9bc74aad5597f51fde6bb53c0b8a76c22ba054241424501015881750a61f36303470033d7a9c4d5654ee4d11983ba73008cbe4af8e0361e62b1e67b58236a4258f17ceed53d11e204528238a412eab6ce3476e9d3eb42c18143fd935464ab466417a2d3b51b750b3047acc94708aa8e69bb01d19e7ba841f428cee631e4d752a4de8130431b63246d695dcc87af881316251bc6d35651f9508a03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140c06424142453402000000000a0000000000000004424142456902010cdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa862701000000000000003a3d45dc55b57bf542f4c6ff41af080ec675317f4ed50ae1d2713bf9f892692d010000000000000054c71c235773b82115f0744252369c13414fd0e8bad3e8feff462c6a4bb58a0f0100000000000000c6e9d02ce38de7b255382f804a64f9bc74aad5597f51fde6bb53c0b8a76c22ba05424142450101e4df6a034d5057b1eace2dd4918f2357c5ab0413615596ebee5129fb0fcf146a087c8b3b65d55f76ebf91a77504e334be9b6a36cb836adf58cfd1756b149b689") //nolint:lll + + decodedProof := BabeEquivocationProof{ + FirstHeader: *NewEmptyHeader(), + SecondHeader: *NewEmptyHeader(), + } + + err := scale.Unmarshal(expectedEncoding, &decodedProof) + require.NoError(t, err) + + actualEncoding, err := scale.Marshal(decodedProof) + require.NoError(t, err) + require.Equal(t, expectedEncoding, actualEncoding) +} diff --git a/lib/babe/errors.go b/lib/babe/errors.go index 9ee788ecd3..857e4a98bb 100644 --- a/lib/babe/errors.go +++ b/lib/babe/errors.go @@ -24,6 +24,9 @@ import ( ) var ( + // ErrAuthIndexOutOfBound is returned when a authority index doesn't exist + ErrAuthIndexOutOfBound = errors.New("authority index doesn't exist") + // ErrBadSlotClaim is returned when a slot claim is invalid ErrBadSlotClaim = errors.New("could not verify slot claim VRF proof") diff --git a/lib/babe/mocks/runtime.go b/lib/babe/mocks/runtime.go new file mode 100644 index 0000000000..305cccae16 --- /dev/null +++ b/lib/babe/mocks/runtime.go @@ -0,0 +1,417 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/dot/core (interfaces: RuntimeInstance) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + types "github.com/ChainSafe/gossamer/dot/types" + common "github.com/ChainSafe/gossamer/lib/common" + keystore "github.com/ChainSafe/gossamer/lib/keystore" + runtime "github.com/ChainSafe/gossamer/lib/runtime" + transaction "github.com/ChainSafe/gossamer/lib/transaction" + gomock "github.com/golang/mock/gomock" +) + +// MockRuntimeInstance is a mock of RuntimeInstance interface. +type MockRuntimeInstance struct { + ctrl *gomock.Controller + recorder *MockRuntimeInstanceMockRecorder +} + +// MockRuntimeInstanceMockRecorder is the mock recorder for MockRuntimeInstance. +type MockRuntimeInstanceMockRecorder struct { + mock *MockRuntimeInstance +} + +// NewMockRuntimeInstance creates a new mock instance. +func NewMockRuntimeInstance(ctrl *gomock.Controller) *MockRuntimeInstance { + mock := &MockRuntimeInstance{ctrl: ctrl} + mock.recorder = &MockRuntimeInstanceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRuntimeInstance) EXPECT() *MockRuntimeInstanceMockRecorder { + return m.recorder +} + +// ApplyExtrinsic mocks base method. +func (m *MockRuntimeInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyExtrinsic", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ApplyExtrinsic indicates an expected call of ApplyExtrinsic. +func (mr *MockRuntimeInstanceMockRecorder) ApplyExtrinsic(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockRuntimeInstance)(nil).ApplyExtrinsic), arg0) +} + +// BabeConfiguration mocks base method. +func (m *MockRuntimeInstance) BabeConfiguration() (*types.BabeConfiguration, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeConfiguration") + ret0, _ := ret[0].(*types.BabeConfiguration) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeConfiguration indicates an expected call of BabeConfiguration. +func (mr *MockRuntimeInstanceMockRecorder) BabeConfiguration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeConfiguration)) +} + +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockRuntimeInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockRuntimeInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockRuntimeInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockRuntimeInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockRuntimeInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + +// CheckInherents mocks base method. +func (m *MockRuntimeInstance) CheckInherents() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "CheckInherents") +} + +// CheckInherents indicates an expected call of CheckInherents. +func (mr *MockRuntimeInstanceMockRecorder) CheckInherents() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockRuntimeInstance)(nil).CheckInherents)) +} + +// DecodeSessionKeys mocks base method. +func (m *MockRuntimeInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecodeSessionKeys", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DecodeSessionKeys indicates an expected call of DecodeSessionKeys. +func (mr *MockRuntimeInstanceMockRecorder) DecodeSessionKeys(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockRuntimeInstance)(nil).DecodeSessionKeys), arg0) +} + +// Exec mocks base method. +func (m *MockRuntimeInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exec", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exec indicates an expected call of Exec. +func (mr *MockRuntimeInstanceMockRecorder) Exec(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockRuntimeInstance)(nil).Exec), arg0, arg1) +} + +// ExecuteBlock mocks base method. +func (m *MockRuntimeInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteBlock", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteBlock indicates an expected call of ExecuteBlock. +func (mr *MockRuntimeInstanceMockRecorder) ExecuteBlock(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockRuntimeInstance)(nil).ExecuteBlock), arg0) +} + +// FinalizeBlock mocks base method. +func (m *MockRuntimeInstance) FinalizeBlock() (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FinalizeBlock") + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FinalizeBlock indicates an expected call of FinalizeBlock. +func (mr *MockRuntimeInstanceMockRecorder) FinalizeBlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockRuntimeInstance)(nil).FinalizeBlock)) +} + +// GenerateSessionKeys mocks base method. +func (m *MockRuntimeInstance) GenerateSessionKeys() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GenerateSessionKeys") +} + +// GenerateSessionKeys indicates an expected call of GenerateSessionKeys. +func (mr *MockRuntimeInstanceMockRecorder) GenerateSessionKeys() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockRuntimeInstance)(nil).GenerateSessionKeys)) +} + +// GetCodeHash mocks base method. +func (m *MockRuntimeInstance) GetCodeHash() common.Hash { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCodeHash") + ret0, _ := ret[0].(common.Hash) + return ret0 +} + +// GetCodeHash indicates an expected call of GetCodeHash. +func (mr *MockRuntimeInstanceMockRecorder) GetCodeHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockRuntimeInstance)(nil).GetCodeHash)) +} + +// GrandpaAuthorities mocks base method. +func (m *MockRuntimeInstance) GrandpaAuthorities() ([]types.Authority, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaAuthorities") + ret0, _ := ret[0].([]types.Authority) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GrandpaAuthorities indicates an expected call of GrandpaAuthorities. +func (mr *MockRuntimeInstanceMockRecorder) GrandpaAuthorities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockRuntimeInstance)(nil).GrandpaAuthorities)) +} + +// InherentExtrinsics mocks base method. +func (m *MockRuntimeInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InherentExtrinsics", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InherentExtrinsics indicates an expected call of InherentExtrinsics. +func (mr *MockRuntimeInstanceMockRecorder) InherentExtrinsics(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockRuntimeInstance)(nil).InherentExtrinsics), arg0) +} + +// InitializeBlock mocks base method. +func (m *MockRuntimeInstance) InitializeBlock(arg0 *types.Header) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitializeBlock", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// InitializeBlock indicates an expected call of InitializeBlock. +func (mr *MockRuntimeInstanceMockRecorder) InitializeBlock(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockRuntimeInstance)(nil).InitializeBlock), arg0) +} + +// Keystore mocks base method. +func (m *MockRuntimeInstance) Keystore() *keystore.GlobalKeystore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Keystore") + ret0, _ := ret[0].(*keystore.GlobalKeystore) + return ret0 +} + +// Keystore indicates an expected call of Keystore. +func (mr *MockRuntimeInstanceMockRecorder) Keystore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockRuntimeInstance)(nil).Keystore)) +} + +// Metadata mocks base method. +func (m *MockRuntimeInstance) Metadata() ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Metadata") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Metadata indicates an expected call of Metadata. +func (mr *MockRuntimeInstanceMockRecorder) Metadata() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockRuntimeInstance)(nil).Metadata)) +} + +// NetworkService mocks base method. +func (m *MockRuntimeInstance) NetworkService() runtime.BasicNetwork { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkService") + ret0, _ := ret[0].(runtime.BasicNetwork) + return ret0 +} + +// NetworkService indicates an expected call of NetworkService. +func (mr *MockRuntimeInstanceMockRecorder) NetworkService() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockRuntimeInstance)(nil).NetworkService)) +} + +// NodeStorage mocks base method. +func (m *MockRuntimeInstance) NodeStorage() runtime.NodeStorage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NodeStorage") + ret0, _ := ret[0].(runtime.NodeStorage) + return ret0 +} + +// NodeStorage indicates an expected call of NodeStorage. +func (mr *MockRuntimeInstanceMockRecorder) NodeStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockRuntimeInstance)(nil).NodeStorage)) +} + +// OffchainWorker mocks base method. +func (m *MockRuntimeInstance) OffchainWorker() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OffchainWorker") +} + +// OffchainWorker indicates an expected call of OffchainWorker. +func (mr *MockRuntimeInstanceMockRecorder) OffchainWorker() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockRuntimeInstance)(nil).OffchainWorker)) +} + +// PaymentQueryInfo mocks base method. +func (m *MockRuntimeInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PaymentQueryInfo", arg0) + ret0, _ := ret[0].(*types.RuntimeDispatchInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PaymentQueryInfo indicates an expected call of PaymentQueryInfo. +func (mr *MockRuntimeInstanceMockRecorder) PaymentQueryInfo(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockRuntimeInstance)(nil).PaymentQueryInfo), arg0) +} + +// RandomSeed mocks base method. +func (m *MockRuntimeInstance) RandomSeed() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RandomSeed") +} + +// RandomSeed indicates an expected call of RandomSeed. +func (mr *MockRuntimeInstanceMockRecorder) RandomSeed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockRuntimeInstance)(nil).RandomSeed)) +} + +// SetContextStorage mocks base method. +func (m *MockRuntimeInstance) SetContextStorage(arg0 runtime.Storage) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetContextStorage", arg0) +} + +// SetContextStorage indicates an expected call of SetContextStorage. +func (mr *MockRuntimeInstanceMockRecorder) SetContextStorage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockRuntimeInstance)(nil).SetContextStorage), arg0) +} + +// Stop mocks base method. +func (m *MockRuntimeInstance) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockRuntimeInstanceMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockRuntimeInstance)(nil).Stop)) +} + +// UpdateRuntimeCode mocks base method. +func (m *MockRuntimeInstance) UpdateRuntimeCode(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateRuntimeCode", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateRuntimeCode indicates an expected call of UpdateRuntimeCode. +func (mr *MockRuntimeInstanceMockRecorder) UpdateRuntimeCode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRuntimeCode", reflect.TypeOf((*MockRuntimeInstance)(nil).UpdateRuntimeCode), arg0) +} + +// ValidateTransaction mocks base method. +func (m *MockRuntimeInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateTransaction", arg0) + ret0, _ := ret[0].(*transaction.Validity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateTransaction indicates an expected call of ValidateTransaction. +func (mr *MockRuntimeInstanceMockRecorder) ValidateTransaction(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockRuntimeInstance)(nil).ValidateTransaction), arg0) +} + +// Validator mocks base method. +func (m *MockRuntimeInstance) Validator() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validator") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Validator indicates an expected call of Validator. +func (mr *MockRuntimeInstanceMockRecorder) Validator() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockRuntimeInstance)(nil).Validator)) +} + +// Version mocks base method. +func (m *MockRuntimeInstance) Version() runtime.Version { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Version") + ret0, _ := ret[0].(runtime.Version) + return ret0 +} + +// Version indicates an expected call of Version. +func (mr *MockRuntimeInstanceMockRecorder) Version() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockRuntimeInstance)(nil).Version)) +} diff --git a/lib/babe/mocks_generate_test.go b/lib/babe/mocks_generate_test.go index 2919d620fc..e8d6ab4386 100644 --- a/lib/babe/mocks_generate_test.go +++ b/lib/babe/mocks_generate_test.go @@ -4,4 +4,6 @@ package babe //go:generate mockgen -destination=mock_telemetry_test.go -package $GOPACKAGE . Telemetry +//go:generate mockgen -destination=mocks/runtime.go -package mocks github.com/ChainSafe/gossamer/dot/core RuntimeInstance +//go:generate mockgen -destination=mocks/network.go -package mocks github.com/ChainSafe/gossamer/dot/core Network //go:generate mockgen -destination=mock_state_test.go -package $GOPACKAGE . BlockState,ImportedBlockNotifierManager,StorageState,TransactionState,EpochState,BlockImportHandler diff --git a/lib/babe/verify.go b/lib/babe/verify.go index 26a3540932..68fa16feb5 100644 --- a/lib/babe/verify.go +++ b/lib/babe/verify.go @@ -330,6 +330,7 @@ func (b *verifier) verifyAuthorshipRight(header *types.Header) error { if err != nil { return fmt.Errorf("could not verify block equivocation: %w", err) } + if equivocated { return fmt.Errorf("%w for block header %s", ErrProducerEquivocated, header.Hash()) } @@ -337,6 +338,46 @@ func (b *verifier) verifyAuthorshipRight(header *types.Header) error { return nil } +func (b *verifier) submitAndReportEquivocation( + slot uint64, authorityIndex uint32, firstHeader, secondHeader types.Header) error { + + // TODO: Check if it is initial sync + // don't report any equivocations during initial sync + // as they are most likely stale. + // https://github.com/ChainSafe/gossamer/issues/3004 + + bestBlockHash := b.blockState.BestBlockHash() + runtimeInstance, err := b.blockState.GetRuntime(bestBlockHash) + if err != nil { + return fmt.Errorf("getting runtime: %w", err) + } + + if len(b.authorities) <= int(authorityIndex) { + return ErrAuthIndexOutOfBound + } + + offenderPublicKey := b.authorities[authorityIndex].ToRaw().Key + + keyOwnershipProof, err := runtimeInstance.BabeGenerateKeyOwnershipProof(slot, offenderPublicKey) + if err != nil { + return fmt.Errorf("getting key ownership proof from runtime: %w", err) + } + + equivocationProof := &types.BabeEquivocationProof{ + Offender: types.AuthorityID(offenderPublicKey), + Slot: slot, + FirstHeader: firstHeader, + SecondHeader: secondHeader, + } + + err = runtimeInstance.BabeSubmitReportEquivocationUnsignedExtrinsic(*equivocationProof, keyOwnershipProof) + if err != nil { + return fmt.Errorf("submitting equivocation report to runtime: %w", err) + } + + return nil +} + // verifyBlockEquivocation checks if the given block's author has occupied the corresponding slot more than once. // It returns true if the block was equivocated. func (b *verifier) verifyBlockEquivocation(header *types.Header) (bool, error) { @@ -374,6 +415,11 @@ func (b *verifier) verifyBlockEquivocation(header *types.Header) (bool, error) { continue } + err = b.submitAndReportEquivocation(slot, authorOfExistingHeader, *existingHeader, *header) + if err != nil { + return true, fmt.Errorf("submitting and reporting equivocation: %w", err) + } + return true, nil } diff --git a/lib/babe/verify_test.go b/lib/babe/verify_test.go index b82706f364..409dd91e6d 100644 --- a/lib/babe/verify_test.go +++ b/lib/babe/verify_test.go @@ -10,6 +10,7 @@ import ( "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/lib/babe/mocks" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" "github.com/ChainSafe/gossamer/pkg/scale" @@ -18,6 +19,10 @@ import ( "github.com/stretchr/testify/require" ) +// this is generated by printing key ownership proof while running `test_generate_equivocation_report_blob` +// https://github.com/paritytech/substrate/blob/ded44948e2d5a398abcb4e342b0513cb690961bb/frame/grandpa/src/benchmarking.rs#L85 +var testKeyOwnershipProof types.OpaqueKeyOwnershipProof = types.OpaqueKeyOwnershipProof([]byte{64, 138, 252, 29, 127, 102, 189, 129, 207, 47, 157, 60, 17, 138, 194, 121, 139, 92, 176, 175, 224, 16, 185, 93, 175, 251, 224, 81, 209, 61, 0, 71}) //nolint:lll + func newTestHeader(t *testing.T, digest ...scale.VaryingDataTypeValue) *types.Header { t.Helper() header := types.NewEmptyHeader() @@ -676,7 +681,6 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { func Test_verifier_verifyBlockEquivocation(t *testing.T) { t.Parallel() - // Generate keys kp, err := sr25519.GenerateKeypair() assert.NoError(t, err) @@ -749,9 +753,42 @@ func Test_verifier_verifyBlockEquivocation(t *testing.T) { []common.Hash{existingHeader.Hash()}, nil) mockBlockState5.EXPECT().GetHeader(existingHeader.Hash()).Return( existingHeader, nil) + mockBlockState5.EXPECT().BestBlockHash().Return(existingHeader.Hash()) verifier5 := newVerifier(mockBlockState5, 1, vi) + const slot = uint64(1) + const authorityIndex = uint32(1) + offenderPublicKey := verifier5.authorities[authorityIndex].ToRaw().Key + keyOwnershipProof := testKeyOwnershipProof + mockRuntime := mocks.NewMockRuntimeInstance(gomock.NewController(t)) + testHeader5.Hash() + + equivocationProof := types.BabeEquivocationProof{ + Offender: offenderPublicKey, + Slot: slot, + FirstHeader: *existingHeader, + SecondHeader: *testHeader5, + } + + mockRuntime.EXPECT().BabeGenerateKeyOwnershipProof(slot, offenderPublicKey).Return(keyOwnershipProof, nil).Times(1) + mockRuntime.EXPECT().BabeSubmitReportEquivocationUnsignedExtrinsic(equivocationProof, keyOwnershipProof).Return(nil) + + mockBlockState5.EXPECT().GetRuntime(existingHeader.Hash()).Return(mockRuntime, nil) + + mockBlockState6 := NewMockBlockState(gomock.NewController(t)) + mockBlockState6.EXPECT().GetBlockHashesBySlot(uint64(1)).Return( + []common.Hash{existingHeader.Hash()}, nil) + mockBlockState6.EXPECT().GetHeader(existingHeader.Hash()).Return( + existingHeader, nil) + mockBlockState6.EXPECT().BestBlockHash().Return(existingHeader.Hash()) + mockBlockState6.EXPECT().GetRuntime(existingHeader.Hash()).Return(nil, errors.New("test error")) + + verifier6 := newVerifier(mockBlockState6, 1, vi) + + testHeader6 := newTestHeader(t, *prd) + testHeader6.Number = 1 + tests := []struct { name string verifier verifier @@ -795,6 +832,13 @@ func Test_verifier_verifyBlockEquivocation(t *testing.T) { equivocated: true, expErr: nil, }, + { + name: "submitting equivocation fails", + verifier: *verifier6, + header: testHeader6, + equivocated: true, + expErr: errors.New("submitting and reporting equivocation: getting runtime: test error"), + }, } for _, tt := range tests { @@ -814,6 +858,82 @@ func Test_verifier_verifyBlockEquivocation(t *testing.T) { } } +func Test_verifier_submitAndReportEquivocation(t *testing.T) { + t.Parallel() + + keyPair, err := sr25519.GenerateKeypair() + require.NoError(t, err) + + auth := types.NewAuthority(keyPair.Public(), uint64(1)) + vi := &verifierInfo{ + authorities: []types.Authority{*auth, *auth}, + threshold: scale.MaxUint128, + } + + ctrl := gomock.NewController(t) + mockBlockState := NewMockBlockState(ctrl) + verifier := newVerifier(mockBlockState, 1, vi) + + const slot = uint64(1) + const authorityIndex = uint32(1) + const epochNumber = uint64(2) + output, proof, err := keyPair.VrfSign(makeTranscript(Randomness{}, slot, epochNumber)) + require.NoError(t, err) + + testDigest := types.BabePrimaryPreDigest{ + AuthorityIndex: authorityIndex, + SlotNumber: slot, + VRFOutput: output, + VRFProof: proof, + } + preRuntimeDigest, err := testDigest.ToPreRuntimeDigest() + require.NoError(t, err) + + firstHeader := newTestHeader(t, *preRuntimeDigest) + firstHash := encodeAndHashHeader(t, firstHeader) + signAndAddSeal(t, keyPair, firstHeader, firstHash[:]) + + output2, proof2, err := keyPair.VrfSign(makeTranscript(Randomness{}, slot, epochNumber)) + require.NoError(t, err) + + digest2 := types.BabePrimaryPreDigest{ + AuthorityIndex: authorityIndex, + SlotNumber: slot, + VRFOutput: output2, + VRFProof: proof2, + } + preRuntimeDigest2, err := digest2.ToPreRuntimeDigest() + require.NoError(t, err) + + secondHeader := newTestHeader(t, *preRuntimeDigest2) + + offenderPublicKey := verifier.authorities[authorityIndex].ToRaw().Key + keyOwnershipProof := testKeyOwnershipProof + mockRuntime := mocks.NewMockRuntimeInstance(ctrl) + + equivocationProof := types.BabeEquivocationProof{ + Offender: offenderPublicKey, + Slot: slot, + FirstHeader: *firstHeader, + SecondHeader: *secondHeader, + } + mockRuntime.EXPECT().BabeGenerateKeyOwnershipProof(slot, offenderPublicKey).Return(keyOwnershipProof, nil).Times(1) + mockRuntime.EXPECT().BabeSubmitReportEquivocationUnsignedExtrinsic(equivocationProof, keyOwnershipProof).Return(nil) + + mockBlockState.EXPECT().BestBlockHash().Return(firstHash).Times(2) + mockBlockState.EXPECT().GetRuntime(firstHash).Return(mockRuntime, nil) + + err = verifier.submitAndReportEquivocation(slot, authorityIndex, *firstHeader, *secondHeader) + assert.NoError(t, err) + + // fails on not being able to get a runtime + mockBlockState.EXPECT().GetRuntime(firstHash).Return(nil, errors.New("test error")) + + err = verifier.submitAndReportEquivocation(slot, authorityIndex, *firstHeader, *secondHeader) + assert.EqualError(t, err, "getting runtime: test error") + +} + func Test_verifier_verifyAuthorshipRightEquivocatory(t *testing.T) { ctrl := gomock.NewController(t) @@ -840,6 +960,7 @@ func Test_verifier_verifyAuthorshipRightEquivocatory(t *testing.T) { assert.NoError(t, err) headerExisting := newTestHeader(t, *prdExisting) + headerExisting.Hash() hashExisting := encodeAndHashHeader(t, headerExisting) signAndAddSeal(t, kp, headerExisting, hashExisting[:]) @@ -875,10 +996,26 @@ func Test_verifier_verifyAuthorshipRightEquivocatory(t *testing.T) { headerEquivocatoryPrimary := newTestHeader(t, *prd1) hashEquivocatoryPrimary := encodeAndHashHeader(t, headerEquivocatoryPrimary) signAndAddSeal(t, kp, headerEquivocatoryPrimary, hashEquivocatoryPrimary[:]) + headerEquivocatoryPrimary.Hash() mockBlockStateEquiv1.EXPECT().GetHeader(hashEquivocatoryPrimary).Return(headerEquivocatoryPrimary, nil) mockBlockStateEquiv1.EXPECT().GetBlockHashesBySlot(uint64(1)).Return( []common.Hash{hashEquivocatoryPrimary, hashExisting}, nil) + mockBlockStateEquiv1.EXPECT().BestBlockHash().Return(hashExisting) + + const slot = uint64(1) + const authorityIndex = uint32(1) + offenderPublicKey := types.AuthorityID(verifierEquivocatoryPrimary.authorities[authorityIndex].ToRaw().Key) + keyOwnershipProof := testKeyOwnershipProof + mockRuntime := mocks.NewMockRuntimeInstance(gomock.NewController(t)) + + mockRuntime.EXPECT().BabeGenerateKeyOwnershipProof(slot, offenderPublicKey).Return(keyOwnershipProof, nil).Times(3) + // equivocationProof changes inside verifyAuthorshipRight, so we can't keep the current value. + mockRuntime.EXPECT().BabeSubmitReportEquivocationUnsignedExtrinsic( + gomock.AssignableToTypeOf(types.BabeEquivocationProof{}), keyOwnershipProof, + ).Return(nil).Times(3) + + mockBlockStateEquiv1.EXPECT().GetRuntime(hashExisting).Return(mockRuntime, nil) // Secondary Plain Test Header testParentPrd, err := testBabeSecondaryPlainPreDigest.ToPreRuntimeDigest() @@ -902,6 +1039,8 @@ func Test_verifier_verifyAuthorshipRightEquivocatory(t *testing.T) { mockBlockStateEquiv2.EXPECT().GetHeader(hashEquivocatorySecondaryPlain).Return(headerEquivocatorySecondaryPlain, nil) mockBlockStateEquiv2.EXPECT().GetBlockHashesBySlot(uint64(1)).Return( []common.Hash{hashEquivocatorySecondaryPlain, hashExisting}, nil) + mockBlockStateEquiv2.EXPECT().BestBlockHash().Return(hashExisting) + mockBlockStateEquiv2.EXPECT().GetRuntime(hashExisting).Return(mockRuntime, nil) // Secondary Vrf Test Header encParentVrfDigest := newEncodedBabeDigest(t, testBabeSecondaryVRFPreDigest) @@ -921,6 +1060,8 @@ func Test_verifier_verifyAuthorshipRightEquivocatory(t *testing.T) { mockBlockStateEquiv3.EXPECT().GetHeader(hashEquivocatorySecondaryVRF).Return(headerEquivocatorySecondaryVRF, nil) mockBlockStateEquiv3.EXPECT().GetBlockHashesBySlot(uint64(1)).Return( []common.Hash{hashEquivocatorySecondaryVRF, hashExisting}, nil) + mockBlockStateEquiv3.EXPECT().BestBlockHash().Return(hashExisting) + mockBlockStateEquiv3.EXPECT().GetRuntime(hashExisting).Return(mockRuntime, nil) tests := []struct { name string diff --git a/lib/blocktree/hashtoruntime_test.go b/lib/blocktree/hashtoruntime_test.go index 2a3544d44a..c63dad4481 100644 --- a/lib/blocktree/hashtoruntime_test.go +++ b/lib/blocktree/hashtoruntime_test.go @@ -35,7 +35,7 @@ func Test_hashToRuntime_get(t *testing.T) { "hash_does_not_exist": { htr: &hashToRuntime{ mapping: map[Hash]Runtime{ - {4, 5, 6}: NewMockInstance(nil), + {4, 5, 6}: NewMockRuntime(nil), }, }, hash: common.Hash{1, 2, 3}, @@ -43,11 +43,11 @@ func Test_hashToRuntime_get(t *testing.T) { "hash_exists": { htr: &hashToRuntime{ mapping: map[Hash]Runtime{ - {1, 2, 3}: NewMockInstance(nil), + {1, 2, 3}: NewMockRuntime(nil), }, }, hash: common.Hash{1, 2, 3}, - instance: NewMockInstance(nil), + instance: NewMockRuntime(nil), }, } @@ -77,17 +77,17 @@ func Test_hashToRuntime_set(t *testing.T) { mapping: map[Hash]Runtime{}, }, hash: common.Hash{1, 2, 3}, - instance: NewMockInstance(nil), + instance: NewMockRuntime(nil), expectedHtr: &hashToRuntime{ mapping: map[Hash]Runtime{ - {1, 2, 3}: NewMockInstance(nil), + {1, 2, 3}: NewMockRuntime(nil), }, }, }, "override_instance": { initialHtr: &hashToRuntime{ mapping: map[Hash]Runtime{ - {1, 2, 3}: NewMockInstance(nil), + {1, 2, 3}: NewMockRuntime(nil), }, }, hash: common.Hash{1, 2, 3}, @@ -134,7 +134,7 @@ func Test_hashToRuntime_delete(t *testing.T) { "hash_deleted": { initialHtr: &hashToRuntime{ mapping: map[Hash]Runtime{ - {1, 2, 3}: NewMockInstance(nil), + {1, 2, 3}: NewMockRuntime(nil), }, }, hash: common.Hash{1, 2, 3}, @@ -192,7 +192,7 @@ func Test_hashToRuntime_threadSafety(t *testing.T) { htr := newHashToRuntime() hash := common.Hash{1, 2, 3} - instance := NewMockInstance(nil) + instance := NewMockRuntime(nil) for i := 0; i < parallelism; i++ { go runInLoop(func() { diff --git a/lib/blocktree/interfaces.go b/lib/blocktree/interfaces.go index ef4cfc73b4..bff6165336 100644 --- a/lib/blocktree/interfaces.go +++ b/lib/blocktree/interfaces.go @@ -35,6 +35,8 @@ type Runtime interface { DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) CheckInherents() + BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error RandomSeed() OffchainWorker() GenerateSessionKeys() diff --git a/lib/blocktree/mocks_generate_test.go b/lib/blocktree/mocks_generate_test.go index b28c8d756b..9ad0122c54 100644 --- a/lib/blocktree/mocks_generate_test.go +++ b/lib/blocktree/mocks_generate_test.go @@ -3,4 +3,4 @@ package blocktree -//go:generate mockgen -destination=mocks_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/lib/runtime Instance +//go:generate mockgen -destination=mocks_test.go -package $GOPACKAGE . Runtime diff --git a/lib/blocktree/mocks_test.go b/lib/blocktree/mocks_test.go index c019ebfcb3..891d75a85a 100644 --- a/lib/blocktree/mocks_test.go +++ b/lib/blocktree/mocks_test.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ChainSafe/gossamer/lib/runtime (interfaces: Instance) +// Source: github.com/ChainSafe/gossamer/lib/blocktree (interfaces: Runtime) // Package blocktree is a generated GoMock package. package blocktree @@ -15,31 +15,31 @@ import ( gomock "github.com/golang/mock/gomock" ) -// MockInstance is a mock of Instance interface. -type MockInstance struct { +// MockRuntime is a mock of Runtime interface. +type MockRuntime struct { ctrl *gomock.Controller - recorder *MockInstanceMockRecorder + recorder *MockRuntimeMockRecorder } -// MockInstanceMockRecorder is the mock recorder for MockInstance. -type MockInstanceMockRecorder struct { - mock *MockInstance +// MockRuntimeMockRecorder is the mock recorder for MockRuntime. +type MockRuntimeMockRecorder struct { + mock *MockRuntime } -// NewMockInstance creates a new mock instance. -func NewMockInstance(ctrl *gomock.Controller) *MockInstance { - mock := &MockInstance{ctrl: ctrl} - mock.recorder = &MockInstanceMockRecorder{mock} +// NewMockRuntime creates a new mock instance. +func NewMockRuntime(ctrl *gomock.Controller) *MockRuntime { + mock := &MockRuntime{ctrl: ctrl} + mock.recorder = &MockRuntimeMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockInstance) EXPECT() *MockInstanceMockRecorder { +func (m *MockRuntime) EXPECT() *MockRuntimeMockRecorder { return m.recorder } // ApplyExtrinsic mocks base method. -func (m *MockInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { +func (m *MockRuntime) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ApplyExtrinsic", arg0) ret0, _ := ret[0].([]byte) @@ -48,13 +48,13 @@ func (m *MockInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { } // ApplyExtrinsic indicates an expected call of ApplyExtrinsic. -func (mr *MockInstanceMockRecorder) ApplyExtrinsic(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) ApplyExtrinsic(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockInstance)(nil).ApplyExtrinsic), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockRuntime)(nil).ApplyExtrinsic), arg0) } // BabeConfiguration mocks base method. -func (m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { +func (m *MockRuntime) BabeConfiguration() (*types.BabeConfiguration, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BabeConfiguration") ret0, _ := ret[0].(*types.BabeConfiguration) @@ -63,25 +63,54 @@ func (m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { } // BabeConfiguration indicates an expected call of BabeConfiguration. -func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { +func (mr *MockRuntimeMockRecorder) BabeConfiguration() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockRuntime)(nil).BabeConfiguration)) +} + +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockRuntime) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockRuntimeMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockRuntime)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockRuntime) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockRuntimeMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockRuntime)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) } // CheckInherents mocks base method. -func (m *MockInstance) CheckInherents() { +func (m *MockRuntime) CheckInherents() { m.ctrl.T.Helper() m.ctrl.Call(m, "CheckInherents") } // CheckInherents indicates an expected call of CheckInherents. -func (mr *MockInstanceMockRecorder) CheckInherents() *gomock.Call { +func (mr *MockRuntimeMockRecorder) CheckInherents() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockInstance)(nil).CheckInherents)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockRuntime)(nil).CheckInherents)) } // DecodeSessionKeys mocks base method. -func (m *MockInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { +func (m *MockRuntime) DecodeSessionKeys(arg0 []byte) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DecodeSessionKeys", arg0) ret0, _ := ret[0].([]byte) @@ -90,13 +119,13 @@ func (m *MockInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { } // DecodeSessionKeys indicates an expected call of DecodeSessionKeys. -func (mr *MockInstanceMockRecorder) DecodeSessionKeys(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) DecodeSessionKeys(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockInstance)(nil).DecodeSessionKeys), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockRuntime)(nil).DecodeSessionKeys), arg0) } // Exec mocks base method. -func (m *MockInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { +func (m *MockRuntime) Exec(arg0 string, arg1 []byte) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Exec", arg0, arg1) ret0, _ := ret[0].([]byte) @@ -105,13 +134,13 @@ func (m *MockInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { } // Exec indicates an expected call of Exec. -func (mr *MockInstanceMockRecorder) Exec(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) Exec(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockInstance)(nil).Exec), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockRuntime)(nil).Exec), arg0, arg1) } // ExecuteBlock mocks base method. -func (m *MockInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { +func (m *MockRuntime) ExecuteBlock(arg0 *types.Block) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ExecuteBlock", arg0) ret0, _ := ret[0].([]byte) @@ -120,13 +149,13 @@ func (m *MockInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { } // ExecuteBlock indicates an expected call of ExecuteBlock. -func (mr *MockInstanceMockRecorder) ExecuteBlock(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) ExecuteBlock(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockInstance)(nil).ExecuteBlock), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockRuntime)(nil).ExecuteBlock), arg0) } // FinalizeBlock mocks base method. -func (m *MockInstance) FinalizeBlock() (*types.Header, error) { +func (m *MockRuntime) FinalizeBlock() (*types.Header, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FinalizeBlock") ret0, _ := ret[0].(*types.Header) @@ -135,25 +164,25 @@ func (m *MockInstance) FinalizeBlock() (*types.Header, error) { } // FinalizeBlock indicates an expected call of FinalizeBlock. -func (mr *MockInstanceMockRecorder) FinalizeBlock() *gomock.Call { +func (mr *MockRuntimeMockRecorder) FinalizeBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockInstance)(nil).FinalizeBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockRuntime)(nil).FinalizeBlock)) } // GenerateSessionKeys mocks base method. -func (m *MockInstance) GenerateSessionKeys() { +func (m *MockRuntime) GenerateSessionKeys() { m.ctrl.T.Helper() m.ctrl.Call(m, "GenerateSessionKeys") } // GenerateSessionKeys indicates an expected call of GenerateSessionKeys. -func (mr *MockInstanceMockRecorder) GenerateSessionKeys() *gomock.Call { +func (mr *MockRuntimeMockRecorder) GenerateSessionKeys() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockInstance)(nil).GenerateSessionKeys)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockRuntime)(nil).GenerateSessionKeys)) } // GetCodeHash mocks base method. -func (m *MockInstance) GetCodeHash() common.Hash { +func (m *MockRuntime) GetCodeHash() common.Hash { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetCodeHash") ret0, _ := ret[0].(common.Hash) @@ -161,13 +190,13 @@ func (m *MockInstance) GetCodeHash() common.Hash { } // GetCodeHash indicates an expected call of GetCodeHash. -func (mr *MockInstanceMockRecorder) GetCodeHash() *gomock.Call { +func (mr *MockRuntimeMockRecorder) GetCodeHash() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockInstance)(nil).GetCodeHash)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockRuntime)(nil).GetCodeHash)) } // GrandpaAuthorities mocks base method. -func (m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { +func (m *MockRuntime) GrandpaAuthorities() ([]types.Authority, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GrandpaAuthorities") ret0, _ := ret[0].([]types.Authority) @@ -176,13 +205,13 @@ func (m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { } // GrandpaAuthorities indicates an expected call of GrandpaAuthorities. -func (mr *MockInstanceMockRecorder) GrandpaAuthorities() *gomock.Call { +func (mr *MockRuntimeMockRecorder) GrandpaAuthorities() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockInstance)(nil).GrandpaAuthorities)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockRuntime)(nil).GrandpaAuthorities)) } // InherentExtrinsics mocks base method. -func (m *MockInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { +func (m *MockRuntime) InherentExtrinsics(arg0 []byte) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InherentExtrinsics", arg0) ret0, _ := ret[0].([]byte) @@ -191,13 +220,13 @@ func (m *MockInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { } // InherentExtrinsics indicates an expected call of InherentExtrinsics. -func (mr *MockInstanceMockRecorder) InherentExtrinsics(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) InherentExtrinsics(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockInstance)(nil).InherentExtrinsics), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockRuntime)(nil).InherentExtrinsics), arg0) } // InitializeBlock mocks base method. -func (m *MockInstance) InitializeBlock(arg0 *types.Header) error { +func (m *MockRuntime) InitializeBlock(arg0 *types.Header) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InitializeBlock", arg0) ret0, _ := ret[0].(error) @@ -205,13 +234,13 @@ func (m *MockInstance) InitializeBlock(arg0 *types.Header) error { } // InitializeBlock indicates an expected call of InitializeBlock. -func (mr *MockInstanceMockRecorder) InitializeBlock(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) InitializeBlock(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockInstance)(nil).InitializeBlock), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockRuntime)(nil).InitializeBlock), arg0) } // Keystore mocks base method. -func (m *MockInstance) Keystore() *keystore.GlobalKeystore { +func (m *MockRuntime) Keystore() *keystore.GlobalKeystore { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Keystore") ret0, _ := ret[0].(*keystore.GlobalKeystore) @@ -219,13 +248,13 @@ func (m *MockInstance) Keystore() *keystore.GlobalKeystore { } // Keystore indicates an expected call of Keystore. -func (mr *MockInstanceMockRecorder) Keystore() *gomock.Call { +func (mr *MockRuntimeMockRecorder) Keystore() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockInstance)(nil).Keystore)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockRuntime)(nil).Keystore)) } // Metadata mocks base method. -func (m *MockInstance) Metadata() ([]byte, error) { +func (m *MockRuntime) Metadata() ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Metadata") ret0, _ := ret[0].([]byte) @@ -234,13 +263,13 @@ func (m *MockInstance) Metadata() ([]byte, error) { } // Metadata indicates an expected call of Metadata. -func (mr *MockInstanceMockRecorder) Metadata() *gomock.Call { +func (mr *MockRuntimeMockRecorder) Metadata() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockInstance)(nil).Metadata)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockRuntime)(nil).Metadata)) } // NetworkService mocks base method. -func (m *MockInstance) NetworkService() runtime.BasicNetwork { +func (m *MockRuntime) NetworkService() runtime.BasicNetwork { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NetworkService") ret0, _ := ret[0].(runtime.BasicNetwork) @@ -248,13 +277,13 @@ func (m *MockInstance) NetworkService() runtime.BasicNetwork { } // NetworkService indicates an expected call of NetworkService. -func (mr *MockInstanceMockRecorder) NetworkService() *gomock.Call { +func (mr *MockRuntimeMockRecorder) NetworkService() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockInstance)(nil).NetworkService)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockRuntime)(nil).NetworkService)) } // NodeStorage mocks base method. -func (m *MockInstance) NodeStorage() runtime.NodeStorage { +func (m *MockRuntime) NodeStorage() runtime.NodeStorage { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NodeStorage") ret0, _ := ret[0].(runtime.NodeStorage) @@ -262,25 +291,25 @@ func (m *MockInstance) NodeStorage() runtime.NodeStorage { } // NodeStorage indicates an expected call of NodeStorage. -func (mr *MockInstanceMockRecorder) NodeStorage() *gomock.Call { +func (mr *MockRuntimeMockRecorder) NodeStorage() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockInstance)(nil).NodeStorage)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockRuntime)(nil).NodeStorage)) } // OffchainWorker mocks base method. -func (m *MockInstance) OffchainWorker() { +func (m *MockRuntime) OffchainWorker() { m.ctrl.T.Helper() m.ctrl.Call(m, "OffchainWorker") } // OffchainWorker indicates an expected call of OffchainWorker. -func (mr *MockInstanceMockRecorder) OffchainWorker() *gomock.Call { +func (mr *MockRuntimeMockRecorder) OffchainWorker() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockInstance)(nil).OffchainWorker)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockRuntime)(nil).OffchainWorker)) } // PaymentQueryInfo mocks base method. -func (m *MockInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { +func (m *MockRuntime) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PaymentQueryInfo", arg0) ret0, _ := ret[0].(*types.RuntimeDispatchInfo) @@ -289,49 +318,49 @@ func (m *MockInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo } // PaymentQueryInfo indicates an expected call of PaymentQueryInfo. -func (mr *MockInstanceMockRecorder) PaymentQueryInfo(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) PaymentQueryInfo(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockInstance)(nil).PaymentQueryInfo), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockRuntime)(nil).PaymentQueryInfo), arg0) } // RandomSeed mocks base method. -func (m *MockInstance) RandomSeed() { +func (m *MockRuntime) RandomSeed() { m.ctrl.T.Helper() m.ctrl.Call(m, "RandomSeed") } // RandomSeed indicates an expected call of RandomSeed. -func (mr *MockInstanceMockRecorder) RandomSeed() *gomock.Call { +func (mr *MockRuntimeMockRecorder) RandomSeed() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockInstance)(nil).RandomSeed)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockRuntime)(nil).RandomSeed)) } // SetContextStorage mocks base method. -func (m *MockInstance) SetContextStorage(arg0 runtime.Storage) { +func (m *MockRuntime) SetContextStorage(arg0 runtime.Storage) { m.ctrl.T.Helper() m.ctrl.Call(m, "SetContextStorage", arg0) } // SetContextStorage indicates an expected call of SetContextStorage. -func (mr *MockInstanceMockRecorder) SetContextStorage(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) SetContextStorage(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockInstance)(nil).SetContextStorage), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockRuntime)(nil).SetContextStorage), arg0) } // Stop mocks base method. -func (m *MockInstance) Stop() { +func (m *MockRuntime) Stop() { m.ctrl.T.Helper() m.ctrl.Call(m, "Stop") } // Stop indicates an expected call of Stop. -func (mr *MockInstanceMockRecorder) Stop() *gomock.Call { +func (mr *MockRuntimeMockRecorder) Stop() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockInstance)(nil).Stop)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockRuntime)(nil).Stop)) } // UpdateRuntimeCode mocks base method. -func (m *MockInstance) UpdateRuntimeCode(arg0 []byte) error { +func (m *MockRuntime) UpdateRuntimeCode(arg0 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateRuntimeCode", arg0) ret0, _ := ret[0].(error) @@ -339,13 +368,13 @@ func (m *MockInstance) UpdateRuntimeCode(arg0 []byte) error { } // UpdateRuntimeCode indicates an expected call of UpdateRuntimeCode. -func (mr *MockInstanceMockRecorder) UpdateRuntimeCode(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) UpdateRuntimeCode(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRuntimeCode", reflect.TypeOf((*MockInstance)(nil).UpdateRuntimeCode), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRuntimeCode", reflect.TypeOf((*MockRuntime)(nil).UpdateRuntimeCode), arg0) } // ValidateTransaction mocks base method. -func (m *MockInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { +func (m *MockRuntime) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidateTransaction", arg0) ret0, _ := ret[0].(*transaction.Validity) @@ -354,13 +383,13 @@ func (m *MockInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.V } // ValidateTransaction indicates an expected call of ValidateTransaction. -func (mr *MockInstanceMockRecorder) ValidateTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockRuntimeMockRecorder) ValidateTransaction(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockInstance)(nil).ValidateTransaction), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockRuntime)(nil).ValidateTransaction), arg0) } // Validator mocks base method. -func (m *MockInstance) Validator() bool { +func (m *MockRuntime) Validator() bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Validator") ret0, _ := ret[0].(bool) @@ -368,13 +397,13 @@ func (m *MockInstance) Validator() bool { } // Validator indicates an expected call of Validator. -func (mr *MockInstanceMockRecorder) Validator() *gomock.Call { +func (mr *MockRuntimeMockRecorder) Validator() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockInstance)(nil).Validator)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockRuntime)(nil).Validator)) } // Version mocks base method. -func (m *MockInstance) Version() runtime.Version { +func (m *MockRuntime) Version() runtime.Version { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Version") ret0, _ := ret[0].(runtime.Version) @@ -382,7 +411,7 @@ func (m *MockInstance) Version() runtime.Version { } // Version indicates an expected call of Version. -func (mr *MockInstanceMockRecorder) Version() *gomock.Call { +func (mr *MockRuntimeMockRecorder) Version() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockInstance)(nil).Version)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockRuntime)(nil).Version)) } diff --git a/lib/runtime/constants.go b/lib/runtime/constants.go index 21034f6a8f..cb6e810238 100644 --- a/lib/runtime/constants.go +++ b/lib/runtime/constants.go @@ -71,6 +71,11 @@ const ( TaggedTransactionQueueValidateTransaction = "TaggedTransactionQueue_validate_transaction" // GrandpaAuthorities is the runtime API call GrandpaApi_grandpa_authorities GrandpaAuthorities = "GrandpaApi_grandpa_authorities" + // BabeAPIGenerateKeyOwnershipProof is the runtime API call BabeApi_generate_key_ownership_proof + BabeAPIGenerateKeyOwnershipProof = "BabeApi_generate_key_ownership_proof" + // BabeAPISubmitReportEquivocationUnsignedExtrinsic is the runtime API call + // BabeApi_submit_report_equivocation_unsigned_extrinsic + BabeAPISubmitReportEquivocationUnsignedExtrinsic = "BabeApi_submit_report_equivocation_unsigned_extrinsic" // BabeAPIConfiguration is the runtime API call BabeApi_configuration BabeAPIConfiguration = "BabeApi_configuration" // BlockBuilderInherentExtrinsics is the runtime API call BlockBuilder_inherent_extrinsics diff --git a/lib/runtime/mocks/mocks.go b/lib/runtime/mocks/mocks.go index a3a2b752af..1109cdf294 100644 --- a/lib/runtime/mocks/mocks.go +++ b/lib/runtime/mocks/mocks.go @@ -68,6 +68,35 @@ func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) } +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + // CheckInherents mocks base method. func (m *MockInstance) CheckInherents() { m.ctrl.T.Helper() diff --git a/lib/runtime/test_helpers.go b/lib/runtime/test_helpers.go index c3b81d9b8d..355c98f05c 100644 --- a/lib/runtime/test_helpers.go +++ b/lib/runtime/test_helpers.go @@ -286,6 +286,8 @@ type Instance interface { ExecuteBlock(block *types.Block) ([]byte, error) DecodeSessionKeys(enc []byte) ([]byte, error) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) + BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error) + BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error CheckInherents() RandomSeed() OffchainWorker() diff --git a/lib/runtime/wasmer/exports.go b/lib/runtime/wasmer/exports.go index c354f4bba7..a86eefc3cb 100644 --- a/lib/runtime/wasmer/exports.go +++ b/lib/runtime/wasmer/exports.go @@ -4,6 +4,7 @@ package wasmer import ( + "bytes" "fmt" "github.com/ChainSafe/gossamer/dot/types" @@ -86,6 +87,55 @@ func (in *Instance) GrandpaAuthorities() ([]types.Authority, error) { return types.GrandpaAuthoritiesRawToAuthorities(gar) } +// BabeGenerateKeyOwnershipProof returns the babe key ownership proof from the runtime. +func (in *Instance) BabeGenerateKeyOwnershipProof(slot uint64, authorityID [32]byte) ( + types.OpaqueKeyOwnershipProof, error) { + + // scale encoded slot uint64 + scale encoded array of 32 bytes + const maxBufferLength = 8 + 33 + buffer := bytes.NewBuffer(make([]byte, 0, maxBufferLength)) + encoder := scale.NewEncoder(buffer) + err := encoder.Encode(slot) + if err != nil { + return nil, fmt.Errorf("encoding slot: %w", err) + } + err = encoder.Encode(authorityID) + if err != nil { + return nil, fmt.Errorf("encoding authority id: %w", err) + } + + encodedKeyOwnershipProof, err := in.Exec(runtime.BabeAPIGenerateKeyOwnershipProof, buffer.Bytes()) + if err != nil { + return nil, fmt.Errorf("executing %s: %w", runtime.BabeAPIGenerateKeyOwnershipProof, err) + } + + keyOwnershipProof := types.OpaqueKeyOwnershipProof{} + err = scale.Unmarshal(encodedKeyOwnershipProof, &keyOwnershipProof) + if err != nil { + return nil, fmt.Errorf("scale decoding key ownership proof: %w", err) + } + + return keyOwnershipProof, nil +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic reports equivocation report to the runtime. +func (in *Instance) BabeSubmitReportEquivocationUnsignedExtrinsic( + equivocationProof types.BabeEquivocationProof, keyOwnershipProof types.OpaqueKeyOwnershipProof, +) error { + buffer := bytes.NewBuffer(nil) + encoder := scale.NewEncoder(buffer) + err := encoder.Encode(equivocationProof) + if err != nil { + return fmt.Errorf("encoding equivocation proof: %w", err) + } + err = encoder.Encode(keyOwnershipProof) + if err != nil { + return fmt.Errorf("encoding key ownership proof: %w", err) + } + _, err = in.Exec(runtime.BabeAPISubmitReportEquivocationUnsignedExtrinsic, buffer.Bytes()) + return err +} + // InitializeBlock calls runtime API function Core_initialise_block func (in *Instance) InitializeBlock(header *types.Header) error { encodedHeader, err := scale.Marshal(*header) diff --git a/lib/runtime/wasmer/exports_test.go b/lib/runtime/wasmer/exports_test.go index 3a217b6605..b5e63b63cd 100644 --- a/lib/runtime/wasmer/exports_test.go +++ b/lib/runtime/wasmer/exports_test.go @@ -28,6 +28,10 @@ import ( "github.com/stretchr/testify/require" ) +// this is generated by printing key ownership proof while running `test_generate_equivocation_report_blob` +// https://github.com/paritytech/substrate/blob/ded44948e2d5a398abcb4e342b0513cb690961bb/frame/grandpa/src/benchmarking.rs#L85 +var testKeyOwnershipProof types.OpaqueKeyOwnershipProof = types.OpaqueKeyOwnershipProof([]byte{64, 138, 252, 29, 127, 102, 189, 129, 207, 47, 157, 60, 17, 138, 194, 121, 139, 92, 176, 175, 224, 16, 185, 93, 175, 251, 224, 81, 209, 61, 0, 71}) //nolint:lll + func Test_Instance_Version(t *testing.T) { t.Parallel() @@ -397,7 +401,7 @@ func TestInstance_GrandpaAuthorities_PolkadotRuntime(t *testing.T) { key := common.MustHexToBytes(genesis.GrandpaAuthoritiesKeyHex) tt.Put(key, value) - rt := NewTestInstanceWithTrie(t, runtime.POLKADOT_RUNTIME, tt) + rt := NewTestInstanceWithTrie(t, runtime.POLKADOT_RUNTIME_v0929, tt) auths, err := rt.GrandpaAuthorities() require.NoError(t, err) @@ -416,6 +420,95 @@ func TestInstance_GrandpaAuthorities_PolkadotRuntime(t *testing.T) { require.Equal(t, expected, auths) } +func TestInstance_BabeGenerateKeyOwnershipProof(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + targetRuntime string + }{ + { + name: "with_polkadot_runtime", + targetRuntime: runtime.POLKADOT_RUNTIME, + }, + { + name: "with_westend_runtime", + targetRuntime: runtime.WESTEND_RUNTIME_v0929, + }, + } + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + tt := trie.NewEmptyTrie() + + randomnessValue, err := common.HexToHash("0x01") + require.NoError(t, err) + key := common.MustHexToBytes(genesis.BABERandomnessKeyHex) + tt.Put(key, randomnessValue[:]) + + authorityValue, err := common.HexToBytes("0x08eea1eabcac7d2c8a6459b7322cf997874482bfc3d2ec7a80888a3a7d714103640100000000000000b64994460e59b30364cad3c92e3df6052f9b0ebbb8f88460c194dc5794d6d7170100000000000000") //nolint:lll + require.NoError(t, err) + + key = common.MustHexToBytes(genesis.BABEAuthoritiesKeyHex) + tt.Put(key, authorityValue) + + rt := NewTestInstanceWithTrie(t, testCase.targetRuntime, tt) + + babeConfig, err := rt.BabeConfiguration() + require.NoError(t, err) + + require.NotEmpty(t, babeConfig.GenesisAuthorities) + + authorityID := babeConfig.GenesisAuthorities[0].Key + + const slot = uint64(10) + _, err = rt.BabeGenerateKeyOwnershipProof(slot, authorityID) + require.NoError(t, err) + }) + } +} + +func TestInstance_BabeSubmitReportEquivocationUnsignedExtrinsic(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + targetRuntime string + }{ + { + name: "with_polkadot_runtime", + targetRuntime: runtime.POLKADOT_RUNTIME, + }, + { + name: "with_westend_runtime", + targetRuntime: runtime.WESTEND_RUNTIME_v0929, + }, + } + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + tt := trie.NewEmptyTrie() + rt := NewTestInstanceWithTrie(t, testCase.targetRuntime, tt) + authorityID := types.AuthorityID{1} + const slot = uint64(1) + + keyOwnershipProof := testKeyOwnershipProof + + equivocationProof := types.BabeEquivocationProof{ + Offender: authorityID, + Slot: slot, + } + + err := rt.BabeSubmitReportEquivocationUnsignedExtrinsic(equivocationProof, keyOwnershipProof) + require.NoError(t, err) + }) + } +} + func TestInstance_BabeConfiguration_NodeRuntime_NoAuthorities(t *testing.T) { rt := NewTestInstance(t, runtime.NODE_RUNTIME) cfg, err := rt.BabeConfiguration() @@ -454,16 +547,16 @@ func TestInstance_BabeConfiguration_DevRuntime_NoAuthorities(t *testing.T) { func TestInstance_BabeConfiguration_NodeRuntime_WithAuthorities(t *testing.T) { tt := trie.NewEmptyTrie() - rvalue, err := common.HexToHash("0x01") + randomnessValue, err := common.HexToHash("0x01") require.NoError(t, err) key := common.MustHexToBytes(genesis.BABERandomnessKeyHex) - tt.Put(key, rvalue[:]) + tt.Put(key, randomnessValue[:]) - avalue, err := common.HexToBytes("0x08eea1eabcac7d2c8a6459b7322cf997874482bfc3d2ec7a80888a3a7d714103640100000000000000b64994460e59b30364cad3c92e3df6052f9b0ebbb8f88460c194dc5794d6d7170100000000000000") //nolint:lll + authorityValue, err := common.HexToBytes("0x08eea1eabcac7d2c8a6459b7322cf997874482bfc3d2ec7a80888a3a7d714103640100000000000000b64994460e59b30364cad3c92e3df6052f9b0ebbb8f88460c194dc5794d6d7170100000000000000") //nolint:lll require.NoError(t, err) key = common.MustHexToBytes(genesis.BABEAuthoritiesKeyHex) - tt.Put(key, avalue) + tt.Put(key, authorityValue) rt := NewTestInstanceWithTrie(t, runtime.NODE_RUNTIME, tt) diff --git a/pkg/scale/decode.go b/pkg/scale/decode.go index aa53fabef3..d4cc4f84a3 100644 --- a/pkg/scale/decode.go +++ b/pkg/scale/decode.go @@ -447,7 +447,7 @@ func (ds *decodeState) decodeMap(dstv reflect.Value) (err error) { return nil } -// decodeStruct decodes a byte array representing a SCALE tuple. The order of data is +// decodeStruct decodes a byte array representing a SCALE tuple. The order of data is // determined by the source tuple in rust, or the struct field order in a go struct func (ds *decodeState) decodeStruct(dstv reflect.Value) (err error) { in := dstv.Interface()