Skip to content

Commit 55de62e

Browse files
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
1 parent 83b3278 commit 55de62e

23 files changed

+1054
-103
lines changed

dot/core/interfaces.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ type RuntimeInstance interface {
4545
DecodeSessionKeys(enc []byte) ([]byte, error)
4646
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
4747
CheckInherents()
48+
BabeGenerateKeyOwnershipProof(slot uint64, authorityID [32]byte) (
49+
types.OpaqueKeyOwnershipProof, error)
50+
BabeSubmitReportEquivocationUnsignedExtrinsic(
51+
equivocationProof types.BabeEquivocationProof,
52+
keyOwnershipProof types.OpaqueKeyOwnershipProof,
53+
) error
4854
RandomSeed()
4955
OffchainWorker()
5056
GenerateSessionKeys()

dot/core/mocks_test.go

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dot/interfaces.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type runtimeInterface interface {
6464
DecodeSessionKeys(enc []byte) ([]byte, error)
6565
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
6666
CheckInherents()
67+
BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error)
68+
BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error
6769
RandomSeed()
6870
OffchainWorker()
6971
GenerateSessionKeys()

dot/rpc/modules/interfaces_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type Runtime interface {
3333
ExecuteBlock(block *types.Block) ([]byte, error)
3434
DecodeSessionKeys(enc []byte) ([]byte, error)
3535
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
36+
BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error)
37+
BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error
3638
CheckInherents()
3739
RandomSeed()
3840
OffchainWorker()

dot/state/interfaces.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ type Runtime interface {
8989
DecodeSessionKeys(enc []byte) ([]byte, error)
9090
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
9191
CheckInherents()
92+
BabeGenerateKeyOwnershipProof(slot uint64, offenderPublicKey [32]byte) (types.OpaqueKeyOwnershipProof, error)
93+
BabeSubmitReportEquivocationUnsignedExtrinsic(types.BabeEquivocationProof, types.OpaqueKeyOwnershipProof) error
9294
RandomSeed()
9395
OffchainWorker()
9496
GenerateSessionKeys()

dot/sync/mock_runtime_test.go

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dot/types/equivocation.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2023 ChainSafe Systems (ON)
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
package types
5+
6+
import "github.com/ChainSafe/gossamer/lib/crypto/sr25519"
7+
8+
// BabeEquivocationProof represents a babe equivocation proof.
9+
// An equivocation happens when a validator produces more than one block on the same slot.
10+
// The proof of equivocation are the given distinct headers that were signed by the validator
11+
// and which include the slot number.
12+
type BabeEquivocationProof struct {
13+
// Offender is the public key of the equivocator.
14+
Offender AuthorityID
15+
// Slot at which the equivocation happened.
16+
Slot uint64
17+
// FirstHeader is the first header involved in the equivocation.
18+
FirstHeader Header
19+
// SecondHeader is the second header involved in the equivocation.
20+
SecondHeader Header
21+
}
22+
23+
// AuthorityID represents a babe authority identifier.
24+
type AuthorityID [sr25519.PublicKeyLength]byte
25+
26+
// OpaqueKeyOwnershipProof is an opaque type used to represent the key ownership proof at the
27+
// runtime API boundary. The inner value is an encoded representation of the actual key
28+
// ownership proof which will be parameterized when defining the runtime. At
29+
// the runtime API boundary this type is unknown and as such we keep this
30+
// opaque representation, implementers of the runtime API will have to make
31+
// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type.
32+
type OpaqueKeyOwnershipProof []byte

dot/types/equivocation_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2022 ChainSafe Systems (ON)
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
package types
5+
6+
import (
7+
"testing"
8+
9+
"github.com/ChainSafe/gossamer/lib/common"
10+
"github.com/ChainSafe/gossamer/pkg/scale"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestEquivocationProof(t *testing.T) {
15+
// To get these bytes run
16+
// https://github.com/paritytech/substrate/blob/17c07af0b953b84dbe89341294e98e586f9b4591/frame/babe/src/tests.rs#L932
17+
expectedEncoding := common.MustHexToBytes("0xdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa86270b0000000000000043fd935464ab466417a2d3b51b750b3047acc94708aa8e69bb01d19e7ba841f428cee631e4d752a4de8130431b63246d695dcc87af881316251bc6d35651f9508a03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140c06424142453402000000000a0000000000000004424142456902010cdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa862701000000000000003a3d45dc55b57bf542f4c6ff41af080ec675317f4ed50ae1d2713bf9f892692d010000000000000054c71c235773b82115f0744252369c13414fd0e8bad3e8feff462c6a4bb58a0f0100000000000000c6e9d02ce38de7b255382f804a64f9bc74aad5597f51fde6bb53c0b8a76c22ba054241424501015881750a61f36303470033d7a9c4d5654ee4d11983ba73008cbe4af8e0361e62b1e67b58236a4258f17ceed53d11e204528238a412eab6ce3476e9d3eb42c18143fd935464ab466417a2d3b51b750b3047acc94708aa8e69bb01d19e7ba841f428cee631e4d752a4de8130431b63246d695dcc87af881316251bc6d35651f9508a03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c1113140c06424142453402000000000a0000000000000004424142456902010cdef12e42f3e487e9b14095aa8d5cc16a33491f1b50dadcf8811d1480f3fa862701000000000000003a3d45dc55b57bf542f4c6ff41af080ec675317f4ed50ae1d2713bf9f892692d010000000000000054c71c235773b82115f0744252369c13414fd0e8bad3e8feff462c6a4bb58a0f0100000000000000c6e9d02ce38de7b255382f804a64f9bc74aad5597f51fde6bb53c0b8a76c22ba05424142450101e4df6a034d5057b1eace2dd4918f2357c5ab0413615596ebee5129fb0fcf146a087c8b3b65d55f76ebf91a77504e334be9b6a36cb836adf58cfd1756b149b689") //nolint:lll
18+
19+
decodedProof := BabeEquivocationProof{
20+
FirstHeader: *NewEmptyHeader(),
21+
SecondHeader: *NewEmptyHeader(),
22+
}
23+
24+
err := scale.Unmarshal(expectedEncoding, &decodedProof)
25+
require.NoError(t, err)
26+
27+
actualEncoding, err := scale.Marshal(decodedProof)
28+
require.NoError(t, err)
29+
require.Equal(t, expectedEncoding, actualEncoding)
30+
}

lib/babe/errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import (
2424
)
2525

2626
var (
27+
// ErrAuthIndexOutOfBound is returned when a authority index doesn't exist
28+
ErrAuthIndexOutOfBound = errors.New("authority index doesn't exist")
29+
2730
// ErrBadSlotClaim is returned when a slot claim is invalid
2831
ErrBadSlotClaim = errors.New("could not verify slot claim VRF proof")
2932

0 commit comments

Comments
 (0)