From 792dd135b6fa57d4904076dd301d33c3345bc12f Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 10 Apr 2025 12:45:18 +0200 Subject: [PATCH 1/5] fix: header signature cleanup --- block/manager.go | 46 ++++++++++------------ block/manager_test.go | 6 ++- node/full.go | 11 +----- pkg/signer/file/local.go | 20 ++++++++++ pkg/signer/noop/signer.go | 61 ++++++++++++++++++++++++++++- pkg/signer/signer.go | 3 ++ pkg/store/store_test.go | 9 +++++ types/header.go | 21 ---------- types/serialization.go | 44 +++++++++++++++++---- types/serialization_test.go | 3 +- types/signed_header.go | 18 +++++++-- types/signed_header_test.go | 13 +++++-- types/signer.go | 41 -------------------- types/utils.go | 77 +++++++++++++++++-------------------- 14 files changed, 214 insertions(+), 159 deletions(-) delete mode 100644 types/signer.go diff --git a/block/manager.go b/block/manager.go index b0d283078d..93d670162c 100644 --- a/block/manager.go +++ b/block/manager.go @@ -14,7 +14,6 @@ import ( "cosmossdk.io/log" goheaderstore "github.com/celestiaorg/go-header/store" ds "github.com/ipfs/go-datastore" - "github.com/libp2p/go-libp2p/core/crypto" "google.golang.org/protobuf/proto" "github.com/rollkit/go-sequencing" @@ -27,6 +26,7 @@ import ( "github.com/rollkit/rollkit/pkg/genesis" "github.com/rollkit/rollkit/pkg/queue" "github.com/rollkit/rollkit/pkg/signer" + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/rollkit/rollkit/pkg/store" "github.com/rollkit/rollkit/types" pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" @@ -180,28 +180,26 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer }} var signature types.Signature - var pubKey crypto.PubKey // The signer is only provided in aggregator nodes. This enables the creation of a signed genesis header, // which includes a public key and a cryptographic signature for the header. // In a full node (non-aggregator), the signer will be nil, and only an unsigned genesis header will be initialized locally. if signer != nil { - pubKey, err = signer.GetPublic() + signature, err = types.GetSignature(header, signer) if err != nil { - return types.State{}, fmt.Errorf("failed to get public key: %w", err) + return types.State{}, fmt.Errorf("failed to get header signature: %w", err) } - signature, err = getSignature(header, signer) + } else { + // If the signer is not provided, create a noop signer from the proposer address + signer, err = noopsigner.NewNoopSignerFromAddress(genesis.ProposerAddress) if err != nil { - return types.State{}, fmt.Errorf("failed to get header signature: %w", err) + return types.State{}, fmt.Errorf("failed to create noop signer: %w", err) } } err = store.SaveBlockData(ctx, &types.SignedHeader{ - Header: header, - Signer: types.Signer{ - PubKey: pubKey, - Address: genesis.ProposerAddress, - }, + Header: header, + Signer: signer, Signature: signature, }, &types.Data{}, @@ -901,6 +899,7 @@ func (m *Manager) HeaderStoreRetrieveLoop(ctx context.Context) { } // early validation to reject junk headers if !m.isUsingExpectedCentralizedSequencer(header) { + fmt.Println("not using expected sequencer 1") continue } m.logger.Debug("header retrieved from p2p header sync", "headerHeight", header.Height(), "daHeight", daHeight) @@ -1111,15 +1110,7 @@ func (m *Manager) fetchHeaders(ctx context.Context, daHeight uint64) (coreda.Res } func (m *Manager) getSignature(header types.Header) (types.Signature, error) { - return getSignature(header, m.proposerKey) -} - -func getSignature(header types.Header, proposerKey signer.Signer) (types.Signature, error) { - b, err := header.MarshalBinary() - if err != nil { - return nil, err - } - return proposerKey.Sign(b) + return types.GetSignature(header, m.proposerKey) } func (m *Manager) getTxsFromBatch() (*BatchData, error) { @@ -1523,10 +1514,16 @@ func (m *Manager) execCommit(ctx context.Context, newState types.State, h *types func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignature *types.Signature, lastHeaderHash types.Hash, lastState types.State, batchData *BatchData) (*types.SignedHeader, *types.Data, error) { data := batchData.Data batchdata := convertBatchDataToBytes(data) - key, err := m.proposerKey.GetPublic() + + // check that the proposer address is the same as the genesis proposer address + address, err := m.proposerKey.GetAddress() if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get proposer address: %w", err) + } + if !bytes.Equal(m.genesis.ProposerAddress, address) { + return nil, nil, fmt.Errorf("proposer address is not the same as the genesis proposer address %x != %x", address, m.genesis.ProposerAddress) } + header := &types.SignedHeader{ Header: types.Header{ Version: types.Version{ @@ -1545,10 +1542,7 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur ProposerAddress: m.genesis.ProposerAddress, }, Signature: *lastSignature, - Signer: types.Signer{ - PubKey: key, - Address: m.genesis.ProposerAddress, - }, + Signer: m.proposerKey, } blockData := &types.Data{ diff --git a/block/manager_test.go b/block/manager_test.go index 806a841bec..3ed86097be 100644 --- a/block/manager_test.go +++ b/block/manager_test.go @@ -354,7 +354,11 @@ func Test_submitBlocksToDA_BlockMarshalErrorCase2(t *testing.T) { // invalidateBlockHeader results in a block header that produces a marshalling error func invalidateBlockHeader(header *types.SignedHeader) { - header.Signer.PubKey = &crypto.Ed25519PublicKey{} + noopSigner, err := noopsigner.NewNoopSignerFromPubKey(&crypto.Ed25519PublicKey{}) + if err != nil { + panic(err) + } + header.Signer = noopSigner } func Test_isProposer(t *testing.T) { diff --git a/node/full.go b/node/full.go index c50c95c048..1d5cdb558c 100644 --- a/node/full.go +++ b/node/full.go @@ -184,22 +184,13 @@ func initBlockManager( gasPrice float64, gasMultiplier float64, ) (*block.Manager, error) { - logger.Debug("Proposer address", "address", genesis.ProposerAddress) - rollGen := genesispkg.NewGenesis( - genesis.ChainID, - genesis.InitialHeight, - genesis.GenesisDAStartHeight, - genesis.ProposerAddress, - nil, - ) - blockManager, err := block.NewManager( ctx, signer, nodeConfig, - rollGen, + genesis, store, exec, sequencer, diff --git a/pkg/signer/file/local.go b/pkg/signer/file/local.go index 928081821e..bf5695476d 100644 --- a/pkg/signer/file/local.go +++ b/pkg/signer/file/local.go @@ -4,6 +4,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" + "crypto/sha256" "encoding/json" "fmt" "io" @@ -272,6 +273,14 @@ func (s *FileSystemSigner) GetPublic() (crypto.PubKey, error) { return s.publicKey, nil } +// GetAddress returns the address of the signer +func (s *FileSystemSigner) GetAddress() ([]byte, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + return getAddress(s.publicKey) +} + // deriveKeyArgon2 uses Argon2id for key derivation func deriveKeyArgon2(passphrase, salt []byte, keyLen uint32) []byte { // Using some default parameters: @@ -303,3 +312,14 @@ func zeroBytes(b []byte) { b[i] = 0 } } + +// getAddress returns the Ed25519 address of the signer. +func getAddress(pubKey crypto.PubKey) ([]byte, error) { + bz, err := pubKey.Raw() + if err != nil { + return nil, err + } + + address := sha256.Sum256(bz) + return address[:], nil +} diff --git a/pkg/signer/noop/signer.go b/pkg/signer/noop/signer.go index 02698e41b5..1f65fde41c 100644 --- a/pkg/signer/noop/signer.go +++ b/pkg/signer/noop/signer.go @@ -1,6 +1,9 @@ package noop import ( + "crypto/sha256" + "fmt" + "github.com/libp2p/go-libp2p/core/crypto" "github.com/rollkit/rollkit/pkg/signer" @@ -11,19 +14,57 @@ import ( type NoopSigner struct { privKey crypto.PrivKey pubKey crypto.PubKey + address []byte } // NewNoopSigner creates a new signer with a fresh Ed25519 key pair. func NewNoopSigner(privKey crypto.PrivKey) (signer.Signer, error) { - - return &NoopSigner{ + sig := &NoopSigner{ privKey: privKey, pubKey: privKey.GetPublic(), + } + + address, err := getAddress(sig.pubKey) + if err != nil { + return nil, err + } + sig.address = address + + return sig, nil +} + +// NewNoopSignerFromPubKey creates a new signer from a public key. +// The returned signer can't be used to sign messages. +func NewNoopSignerFromPubKey(pubKey crypto.PubKey) (signer.Signer, error) { + sig := &NoopSigner{ + pubKey: pubKey, + } + + if pubKey == nil { + return sig, nil + } + + address, err := getAddress(sig.pubKey) + if err != nil { + return nil, err + } + sig.address = address + + return sig, nil +} + +// NewNoopSignerFromAddress creates a new signer from an address. +func NewNoopSignerFromAddress(address []byte) (signer.Signer, error) { + return &NoopSigner{ + address: address, }, nil } // Sign implements the Signer interface by signing the message with the Ed25519 private key. func (n *NoopSigner) Sign(message []byte) ([]byte, error) { + if n.privKey == nil { + return nil, fmt.Errorf("private key not loaded") + } return n.privKey.Sign(message) } @@ -31,3 +72,19 @@ func (n *NoopSigner) Sign(message []byte) ([]byte, error) { func (n *NoopSigner) GetPublic() (crypto.PubKey, error) { return n.pubKey, nil } + +// GetAddress implements the Signer interface by returning the Ed25519 address. +func (n *NoopSigner) GetAddress() ([]byte, error) { + return n.address, nil +} + +// getAddress returns the Ed25519 address of the signer. +func getAddress(pubKey crypto.PubKey) ([]byte, error) { + bz, err := pubKey.Raw() + if err != nil { + return nil, err + } + + address := sha256.Sum256(bz) + return address[:], nil +} diff --git a/pkg/signer/signer.go b/pkg/signer/signer.go index ccbb50216d..09c6b951b4 100644 --- a/pkg/signer/signer.go +++ b/pkg/signer/signer.go @@ -11,4 +11,7 @@ type Signer interface { // GetPublic returns the public key paired with this private key. GetPublic() (crypto.PubKey, error) + + // GetAddress returns the address of the signer. + GetAddress() ([]byte, error) } diff --git a/pkg/store/store_test.go b/pkg/store/store_test.go index 48b39958d8..edf577005a 100644 --- a/pkg/store/store_test.go +++ b/pkg/store/store_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/rollkit/rollkit/types" ) @@ -111,6 +112,14 @@ func TestStoreLoad(t *testing.T) { assert.NoError(err) assert.NotNil(header) assert.NotNil(data) + + // replace the signer with a pubkey only signer in the expected header + pubkey, err := expectedHeader.Signer.GetPublic() + require.NoError(err) + noopSigner, err := noopsigner.NewNoopSignerFromPubKey(pubkey) + require.NoError(err) + expectedHeader.Signer = noopSigner + assert.Equal(expectedHeader, header) assert.Equal(expectedData, data) diff --git a/types/header.go b/types/header.go index c7ac7c394c..f19be2eece 100644 --- a/types/header.go +++ b/types/header.go @@ -8,10 +8,6 @@ import ( "time" "github.com/celestiaorg/go-header" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/timestamppb" - - v1 "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) // Hash is a 32-byte array which is used to represent a hash result. @@ -123,23 +119,6 @@ func (h *Header) ValidateBasic() error { return nil } -// Vote returns a vote for the header. -func (h *Header) Vote() ([]byte, error) { - v := &v1.Vote{ - ChainId: h.ChainID(), - Height: h.Height(), - BlockIdHash: h.Hash(), - ValidatorAddress: h.ProposerAddress, - Timestamp: timestamppb.New(h.Time()), - } - - bz, err := proto.Marshal(v) - if err != nil { - return nil, err - } - return bz, nil -} - var _ header.Header[*Header] = &Header{} var _ encoding.BinaryMarshaler = &Header{} var _ encoding.BinaryUnmarshaler = &Header{} diff --git a/types/serialization.go b/types/serialization.go index 969ae42ce1..ba37bf8820 100644 --- a/types/serialization.go +++ b/types/serialization.go @@ -1,10 +1,14 @@ package types import ( + "fmt" + "github.com/libp2p/go-libp2p/core/crypto" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/rollkit/rollkit/pkg/signer/noop" + pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) @@ -58,7 +62,8 @@ func (d *Data) UnmarshalBinary(data []byte) error { // ToProto converts SignedHeader into protobuf representation and returns it. func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { - if sh.Signer.PubKey == nil { + if sh.Signer == nil { + fmt.Println("signer is nil") return &pb.SignedHeader{ Header: sh.Header.ToProto(), Signature: sh.Signature[:], @@ -66,21 +71,43 @@ func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { }, nil } - pubKey, err := crypto.MarshalPublicKey(sh.Signer.PubKey) + pubkey, err := sh.Signer.GetPublic() if err != nil { + fmt.Println("error getting public key", err) return nil, err } + + if pubkey == nil { + fmt.Println("pubkey is nil") + return &pb.SignedHeader{ + Header: sh.Header.ToProto(), + Signature: sh.Signature[:], + Signer: &pb.Signer{}, + }, nil + } + + pubKey, err := crypto.MarshalPublicKey(pubkey) + if err != nil { + return nil, err + } + + signerAddress, err := sh.Signer.GetAddress() + if err != nil { + return nil, err + } + return &pb.SignedHeader{ Header: sh.Header.ToProto(), Signature: sh.Signature[:], Signer: &pb.Signer{ - Address: sh.Signer.Address, + Address: signerAddress, PubKey: pubKey, }, }, nil } -// FromProto fills SignedHeader with data from protobuf representation. +// FromProto fills SignedHeader with data from protobuf representation. The contained +// Signer can only be used to verify signatures, not to sign messages. func (sh *SignedHeader) FromProto(other *pb.SignedHeader) error { err := sh.Header.FromProto(other.Header) if err != nil { @@ -93,10 +120,13 @@ func (sh *SignedHeader) FromProto(other *pb.SignedHeader) error { if err != nil { return err } - sh.Signer = Signer{ - Address: other.Signer.Address, - PubKey: pubKey, + + sig, err := noop.NewNoopSignerFromPubKey(pubKey) + if err != nil { + return err } + + sh.Signer = sig } return nil } diff --git a/types/serialization_test.go b/types/serialization_test.go index 2dd8cf0830..ba30adc2f6 100644 --- a/types/serialization_test.go +++ b/types/serialization_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) @@ -48,7 +49,7 @@ func TestBlockSerializationRoundTrip(t *testing.T) { pubKey1, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(err) - signer1, err := NewSigner(pubKey1.GetPublic()) + signer1, err := noopsigner.NewNoopSignerFromPubKey(pubKey1.GetPublic()) require.NoError(err) cases := []struct { diff --git a/types/signed_header.go b/types/signed_header.go index f894572aaa..ff31f330af 100644 --- a/types/signed_header.go +++ b/types/signed_header.go @@ -6,6 +6,8 @@ import ( "fmt" "github.com/celestiaorg/go-header" + + "github.com/rollkit/rollkit/pkg/signer" ) var ( @@ -23,7 +25,7 @@ type SignedHeader struct { Header // Note: This is backwards compatible as ABCI exported types are not affected. Signature Signature - Signer Signer + Signer signer.Signer } // New creates a new SignedHeader. @@ -102,18 +104,26 @@ func (sh *SignedHeader) ValidateBasic() error { } // Check that the proposer address in the signed header matches the proposer address in the validator set - if !bytes.Equal(sh.ProposerAddress, sh.Signer.Address) { + signerAddress, err := sh.Signer.GetAddress() + if err != nil { + return err + } + if !bytes.Equal(sh.ProposerAddress, signerAddress) { return ErrProposerAddressMismatch } signature := sh.Signature - vote, err := sh.Header.Vote() + bz, err := sh.Header.MarshalBinary() if err != nil { return err } - verified, err := sh.Signer.PubKey.Verify(vote, signature) + pubkey, err := sh.Signer.GetPublic() + if err != nil { + return err + } + verified, err := pubkey.Verify(bz, signature) if err != nil { return err } diff --git a/types/signed_header_test.go b/types/signed_header_test.go index 3866417da6..0ae3b94206 100644 --- a/types/signed_header_test.go +++ b/types/signed_header_test.go @@ -6,6 +6,7 @@ import ( "github.com/celestiaorg/go-header" "github.com/libp2p/go-libp2p/core/crypto" + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -97,9 +98,11 @@ func testVerify(t *testing.T, trusted *SignedHeader, untrustedAdj *SignedHeader, preparedHeader, shouldRecomputeCommit := test.prepare() if shouldRecomputeCommit { - signature, err := GetSignature(preparedHeader.Header, privKey) + noopSigner, err := noopsigner.NewNoopSigner(privKey) require.NoError(t, err) - preparedHeader.Signature = *signature + signature, err := GetSignature(preparedHeader.Header, noopSigner) + require.NoError(t, err) + preparedHeader.Signature = signature } err := trusted.Verify(preparedHeader) @@ -211,9 +214,11 @@ func testValidateBasic(t *testing.T, untrustedAdj *SignedHeader, privKey crypto. preparedHeader, shouldRecomputeCommit := test.prepare() if shouldRecomputeCommit { - signature, err := GetSignature(preparedHeader.Header, privKey) + noopSigner, err := noopsigner.NewNoopSigner(privKey) + require.NoError(t, err) + signature, err := GetSignature(preparedHeader.Header, noopSigner) require.NoError(t, err) - preparedHeader.Signature = *signature + preparedHeader.Signature = signature } err := preparedHeader.ValidateBasic() diff --git a/types/signer.go b/types/signer.go deleted file mode 100644 index af8498a75f..0000000000 --- a/types/signer.go +++ /dev/null @@ -1,41 +0,0 @@ -package types - -import ( - "crypto/sha256" - - "github.com/libp2p/go-libp2p/core/crypto" -) - -// Signer is a type that can verify messages. -type Signer struct { - PubKey crypto.PubKey - Address []byte -} - -// NewSigner creates a new signer from a public key. -func NewSigner(pubKey crypto.PubKey) (Signer, error) { - bz, err := pubKey.Raw() - if err != nil { - return Signer{}, err - } - - address := sha256.Sum256(bz) - return Signer{ - PubKey: pubKey, - Address: address[:], - }, nil -} - -// Verify verifies a vote with a signature. -func (s *Signer) Verify(vote []byte, signature []byte) (bool, error) { - return s.PubKey.Verify(vote, signature) -} - -func KeyAddress(pubKey crypto.PubKey) []byte { - bz, err := pubKey.Raw() - if err != nil { - return nil - } - hash := sha256.Sum256(bz) - return hash[:] -} diff --git a/types/utils.go b/types/utils.go index 3625e6c0b4..43b8437eb6 100644 --- a/types/utils.go +++ b/types/utils.go @@ -2,7 +2,6 @@ package types import ( cryptoRand "crypto/rand" - "errors" "math/rand" "time" @@ -10,31 +9,13 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/rollkit/rollkit/pkg/genesis" + "github.com/rollkit/rollkit/pkg/signer" + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" ) // DefaultSigningKeyType is the key type used by the sequencer signing key const DefaultSigningKeyType = "ed25519" -// ValidatorConfig carries all necessary state for generating a Validator -type ValidatorConfig struct { - PrivKey crypto.PrivKey - VotingPower int64 -} - -// GetValidatorSetCustom returns a validator set based on the provided validatorConfig. -func GetValidatorSetCustom(config ValidatorConfig) (Signer, error) { - if config.PrivKey == nil { - panic(errors.New("private key is nil")) - } - pubKey := config.PrivKey.GetPublic() - - signer, err := NewSigner(pubKey) - if err != nil { - return Signer{}, err - } - return signer, nil -} - // BlockConfig carries all necessary state for block generation type BlockConfig struct { Height uint64 @@ -159,7 +140,7 @@ func GetRandomSignedHeader(chainID string) (*SignedHeader, crypto.PrivKey, error // GetRandomSignedHeaderCustom creates a signed header based on the provided HeaderConfig. func GetRandomSignedHeaderCustom(config *HeaderConfig, chainID string) (*SignedHeader, error) { - signer, err := NewSigner(config.PrivKey.GetPublic()) + signer, err := noopsigner.NewNoopSigner(config.PrivKey) if err != nil { return nil, err } @@ -168,17 +149,23 @@ func GetRandomSignedHeaderCustom(config *HeaderConfig, chainID string) (*SignedH Header: GetRandomHeader(chainID), Signer: signer, } + + signerAddress, err := signer.GetAddress() + if err != nil { + return nil, err + } + signedHeader.Header.BaseHeader.Height = config.Height signedHeader.Header.DataHash = config.DataHash - signedHeader.Header.ProposerAddress = signer.Address - signedHeader.Header.ValidatorHash = signer.Address + signedHeader.Header.ProposerAddress = signerAddress + signedHeader.Header.ValidatorHash = signerAddress signedHeader.Header.BaseHeader.Time = uint64(time.Now().UnixNano()) + (config.Height)*10 - signature, err := GetSignature(signedHeader.Header, config.PrivKey) + signature, err := GetSignature(signedHeader.Header, signer) if err != nil { return nil, err } - signedHeader.Signature = *signature + signedHeader.Signature = signature return signedHeader, nil } @@ -190,20 +177,26 @@ func GetRandomNextSignedHeader(signedHeader *SignedHeader, privKey crypto.PrivKe Signer: signedHeader.Signer, } - signature, err := GetSignature(newSignedHeader.Header, privKey) + signature, err := GetSignature(newSignedHeader.Header, signedHeader.Signer) if err != nil { return nil, err } - newSignedHeader.Signature = *signature + newSignedHeader.Signature = signature return newSignedHeader, nil } // GetFirstSignedHeader creates a 1st signed header for a chain, given a valset and signing key. func GetFirstSignedHeader(privkey crypto.PrivKey, chainID string) (*SignedHeader, error) { - signer, err := NewSigner(privkey.GetPublic()) + signer, err := noopsigner.NewNoopSigner(privkey) if err != nil { return nil, err } + + signerAddress, err := signer.GetAddress() + if err != nil { + return nil, err + } + header := Header{ BaseHeader: BaseHeader{ Height: 1, @@ -218,17 +211,17 @@ func GetFirstSignedHeader(privkey crypto.PrivKey, chainID string) (*SignedHeader LastCommitHash: GetRandomBytes(32), DataHash: GetRandomBytes(32), AppHash: make([]byte, 32), - ProposerAddress: signer.Address, + ProposerAddress: signerAddress, } signedHeader := SignedHeader{ Header: header, Signer: signer, } - signature, err := GetSignature(header, privkey) + signature, err := GetSignature(header, signer) if err != nil { return nil, err } - signedHeader.Signature = *signature + signedHeader.Signature = signature return &signedHeader, nil } @@ -239,7 +232,12 @@ func GetGenesisWithPrivkey(chainID string) (genesis.Genesis, crypto.PrivKey, cry panic(err) } - signer, err := NewSigner(pubKey) + signer, err := noopsigner.NewNoopSigner(privKey) + if err != nil { + panic(err) + } + + signerAddress, err := signer.GetAddress() if err != nil { panic(err) } @@ -248,7 +246,7 @@ func GetGenesisWithPrivkey(chainID string) (genesis.Genesis, crypto.PrivKey, cry chainID, 1, time.Now().UTC(), - signer.Address, + signerAddress, nil, ), privKey, pubKey } @@ -270,17 +268,12 @@ func GetRandomBytes(n uint) []byte { } // GetSignature returns a signature from the given private key over the given header -func GetSignature(header Header, privKey crypto.PrivKey) (*Signature, error) { - consensusVote, err := header.Vote() - if err != nil { - return nil, err - } - sign, err := privKey.Sign(consensusVote) +func GetSignature(header Header, proposerKey signer.Signer) (Signature, error) { + b, err := header.MarshalBinary() if err != nil { return nil, err } - signature := Signature(sign) - return &signature, nil + return proposerKey.Sign(b) } func getBlockDataWith(nTxs int) *Data { From e58d9687bf08215a88f9ded8a897b5140bb33871 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 10 Apr 2025 12:47:27 +0200 Subject: [PATCH 2/5] lint fix --- types/serialization.go | 1 - types/signed_header_test.go | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/serialization.go b/types/serialization.go index ba37bf8820..c61750c61d 100644 --- a/types/serialization.go +++ b/types/serialization.go @@ -8,7 +8,6 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/rollkit/rollkit/pkg/signer/noop" - pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) diff --git a/types/signed_header_test.go b/types/signed_header_test.go index 0ae3b94206..155761e67d 100644 --- a/types/signed_header_test.go +++ b/types/signed_header_test.go @@ -6,9 +6,10 @@ import ( "github.com/celestiaorg/go-header" "github.com/libp2p/go-libp2p/core/crypto" - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" ) func TestSignedHeader(t *testing.T) { From bd0b23ddd9ca016374130b7cfa8e5640168cffa9 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 10 Apr 2025 17:08:02 +0200 Subject: [PATCH 3/5] rollback --- block/manager.go | 42 ++++++++++++++++++++++++++----------- block/manager_test.go | 6 +----- pkg/signer/noop/signer.go | 27 ------------------------ pkg/store/store_test.go | 8 ------- types/serialization.go | 38 ++++++--------------------------- types/serialization_test.go | 3 +-- types/signed_header.go | 20 ++++-------------- types/signed_header_test.go | 10 ++------- types/utils.go | 39 ++++++++++------------------------ 9 files changed, 55 insertions(+), 138 deletions(-) diff --git a/block/manager.go b/block/manager.go index 93d670162c..fd5c9d4f59 100644 --- a/block/manager.go +++ b/block/manager.go @@ -14,6 +14,7 @@ import ( "cosmossdk.io/log" goheaderstore "github.com/celestiaorg/go-header/store" ds "github.com/ipfs/go-datastore" + "github.com/libp2p/go-libp2p/core/crypto" "google.golang.org/protobuf/proto" "github.com/rollkit/go-sequencing" @@ -26,7 +27,6 @@ import ( "github.com/rollkit/rollkit/pkg/genesis" "github.com/rollkit/rollkit/pkg/queue" "github.com/rollkit/rollkit/pkg/signer" - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/rollkit/rollkit/pkg/store" "github.com/rollkit/rollkit/types" pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" @@ -180,26 +180,29 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer }} var signature types.Signature + var pubKey crypto.PubKey // The signer is only provided in aggregator nodes. This enables the creation of a signed genesis header, // which includes a public key and a cryptographic signature for the header. // In a full node (non-aggregator), the signer will be nil, and only an unsigned genesis header will be initialized locally. if signer != nil { - signature, err = types.GetSignature(header, signer) + pubKey, err = signer.GetPublic() if err != nil { - return types.State{}, fmt.Errorf("failed to get header signature: %w", err) + return types.State{}, fmt.Errorf("failed to get public key: %w", err) } - } else { - // If the signer is not provided, create a noop signer from the proposer address - signer, err = noopsigner.NewNoopSignerFromAddress(genesis.ProposerAddress) + + signature, err = getSignature(header, signer) if err != nil { - return types.State{}, fmt.Errorf("failed to create noop signer: %w", err) + return types.State{}, fmt.Errorf("failed to get header signature: %w", err) } } err = store.SaveBlockData(ctx, &types.SignedHeader{ - Header: header, - Signer: signer, + Header: header, + Signer: types.Signer{ + PubKey: pubKey, + Address: genesis.ProposerAddress, + }, Signature: signature, }, &types.Data{}, @@ -899,7 +902,6 @@ func (m *Manager) HeaderStoreRetrieveLoop(ctx context.Context) { } // early validation to reject junk headers if !m.isUsingExpectedCentralizedSequencer(header) { - fmt.Println("not using expected sequencer 1") continue } m.logger.Debug("header retrieved from p2p header sync", "headerHeight", header.Height(), "daHeight", daHeight) @@ -1110,7 +1112,7 @@ func (m *Manager) fetchHeaders(ctx context.Context, daHeight uint64) (coreda.Res } func (m *Manager) getSignature(header types.Header) (types.Signature, error) { - return types.GetSignature(header, m.proposerKey) + return getSignature(header, m.proposerKey) } func (m *Manager) getTxsFromBatch() (*BatchData, error) { @@ -1515,6 +1517,11 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur data := batchData.Data batchdata := convertBatchDataToBytes(data) + key, err := m.proposerKey.GetPublic() + if err != nil { + return nil, nil, fmt.Errorf("failed to get proposer public key: %w", err) + } + // check that the proposer address is the same as the genesis proposer address address, err := m.proposerKey.GetAddress() if err != nil { @@ -1542,7 +1549,10 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur ProposerAddress: m.genesis.ProposerAddress, }, Signature: *lastSignature, - Signer: m.proposerKey, + Signer: types.Signer{ + PubKey: key, + Address: m.genesis.ProposerAddress, + }, } blockData := &types.Data{ @@ -1655,3 +1665,11 @@ func bytesToBatchData(data []byte) ([][]byte, error) { return result, nil } + +func getSignature(header types.Header, proposerKey signer.Signer) (types.Signature, error) { + b, err := header.MarshalBinary() + if err != nil { + return nil, err + } + return proposerKey.Sign(b) +} diff --git a/block/manager_test.go b/block/manager_test.go index 3ed86097be..806a841bec 100644 --- a/block/manager_test.go +++ b/block/manager_test.go @@ -354,11 +354,7 @@ func Test_submitBlocksToDA_BlockMarshalErrorCase2(t *testing.T) { // invalidateBlockHeader results in a block header that produces a marshalling error func invalidateBlockHeader(header *types.SignedHeader) { - noopSigner, err := noopsigner.NewNoopSignerFromPubKey(&crypto.Ed25519PublicKey{}) - if err != nil { - panic(err) - } - header.Signer = noopSigner + header.Signer.PubKey = &crypto.Ed25519PublicKey{} } func Test_isProposer(t *testing.T) { diff --git a/pkg/signer/noop/signer.go b/pkg/signer/noop/signer.go index 1f65fde41c..1718d88022 100644 --- a/pkg/signer/noop/signer.go +++ b/pkg/signer/noop/signer.go @@ -33,33 +33,6 @@ func NewNoopSigner(privKey crypto.PrivKey) (signer.Signer, error) { return sig, nil } -// NewNoopSignerFromPubKey creates a new signer from a public key. -// The returned signer can't be used to sign messages. -func NewNoopSignerFromPubKey(pubKey crypto.PubKey) (signer.Signer, error) { - sig := &NoopSigner{ - pubKey: pubKey, - } - - if pubKey == nil { - return sig, nil - } - - address, err := getAddress(sig.pubKey) - if err != nil { - return nil, err - } - sig.address = address - - return sig, nil -} - -// NewNoopSignerFromAddress creates a new signer from an address. -func NewNoopSignerFromAddress(address []byte) (signer.Signer, error) { - return &NoopSigner{ - address: address, - }, nil -} - // Sign implements the Signer interface by signing the message with the Ed25519 private key. func (n *NoopSigner) Sign(message []byte) ([]byte, error) { if n.privKey == nil { diff --git a/pkg/store/store_test.go b/pkg/store/store_test.go index edf577005a..def03eee14 100644 --- a/pkg/store/store_test.go +++ b/pkg/store/store_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" "github.com/rollkit/rollkit/types" ) @@ -113,13 +112,6 @@ func TestStoreLoad(t *testing.T) { assert.NotNil(header) assert.NotNil(data) - // replace the signer with a pubkey only signer in the expected header - pubkey, err := expectedHeader.Signer.GetPublic() - require.NoError(err) - noopSigner, err := noopsigner.NewNoopSignerFromPubKey(pubkey) - require.NoError(err) - expectedHeader.Signer = noopSigner - assert.Equal(expectedHeader, header) assert.Equal(expectedData, data) diff --git a/types/serialization.go b/types/serialization.go index c61750c61d..746488c07b 100644 --- a/types/serialization.go +++ b/types/serialization.go @@ -1,13 +1,10 @@ package types import ( - "fmt" - "github.com/libp2p/go-libp2p/core/crypto" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" - "github.com/rollkit/rollkit/pkg/signer/noop" pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) @@ -61,23 +58,7 @@ func (d *Data) UnmarshalBinary(data []byte) error { // ToProto converts SignedHeader into protobuf representation and returns it. func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { - if sh.Signer == nil { - fmt.Println("signer is nil") - return &pb.SignedHeader{ - Header: sh.Header.ToProto(), - Signature: sh.Signature[:], - Signer: &pb.Signer{}, - }, nil - } - - pubkey, err := sh.Signer.GetPublic() - if err != nil { - fmt.Println("error getting public key", err) - return nil, err - } - - if pubkey == nil { - fmt.Println("pubkey is nil") + if sh.Signer.PubKey == nil { return &pb.SignedHeader{ Header: sh.Header.ToProto(), Signature: sh.Signature[:], @@ -85,12 +66,7 @@ func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { }, nil } - pubKey, err := crypto.MarshalPublicKey(pubkey) - if err != nil { - return nil, err - } - - signerAddress, err := sh.Signer.GetAddress() + pubKey, err := crypto.MarshalPublicKey(sh.Signer.PubKey) if err != nil { return nil, err } @@ -99,7 +75,7 @@ func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { Header: sh.Header.ToProto(), Signature: sh.Signature[:], Signer: &pb.Signer{ - Address: signerAddress, + Address: sh.Signer.Address, PubKey: pubKey, }, }, nil @@ -120,12 +96,10 @@ func (sh *SignedHeader) FromProto(other *pb.SignedHeader) error { return err } - sig, err := noop.NewNoopSignerFromPubKey(pubKey) - if err != nil { - return err + sh.Signer = Signer{ + Address: other.Signer.Address, + PubKey: pubKey, } - - sh.Signer = sig } return nil } diff --git a/types/serialization_test.go b/types/serialization_test.go index ba30adc2f6..2dd8cf0830 100644 --- a/types/serialization_test.go +++ b/types/serialization_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" pb "github.com/rollkit/rollkit/types/pb/rollkit/v1" ) @@ -49,7 +48,7 @@ func TestBlockSerializationRoundTrip(t *testing.T) { pubKey1, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(err) - signer1, err := noopsigner.NewNoopSignerFromPubKey(pubKey1.GetPublic()) + signer1, err := NewSigner(pubKey1.GetPublic()) require.NoError(err) cases := []struct { diff --git a/types/signed_header.go b/types/signed_header.go index ff31f330af..15c62f9085 100644 --- a/types/signed_header.go +++ b/types/signed_header.go @@ -6,8 +6,6 @@ import ( "fmt" "github.com/celestiaorg/go-header" - - "github.com/rollkit/rollkit/pkg/signer" ) var ( @@ -25,7 +23,7 @@ type SignedHeader struct { Header // Note: This is backwards compatible as ABCI exported types are not affected. Signature Signature - Signer signer.Signer + Signer Signer } // New creates a new SignedHeader. @@ -104,33 +102,23 @@ func (sh *SignedHeader) ValidateBasic() error { } // Check that the proposer address in the signed header matches the proposer address in the validator set - signerAddress, err := sh.Signer.GetAddress() - if err != nil { - return err - } - if !bytes.Equal(sh.ProposerAddress, signerAddress) { + if !bytes.Equal(sh.ProposerAddress, sh.Signer.Address) { return ErrProposerAddressMismatch } - signature := sh.Signature - bz, err := sh.Header.MarshalBinary() if err != nil { return err } - pubkey, err := sh.Signer.GetPublic() + verified, err := sh.Signer.PubKey.Verify(bz, sh.Signature) if err != nil { return err } - verified, err := pubkey.Verify(bz, signature) - if err != nil { - return err - } - if !verified { return ErrSignatureVerificationFailed } + return nil } diff --git a/types/signed_header_test.go b/types/signed_header_test.go index 155761e67d..bddfada5b7 100644 --- a/types/signed_header_test.go +++ b/types/signed_header_test.go @@ -8,8 +8,6 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" ) func TestSignedHeader(t *testing.T) { @@ -99,9 +97,7 @@ func testVerify(t *testing.T, trusted *SignedHeader, untrustedAdj *SignedHeader, preparedHeader, shouldRecomputeCommit := test.prepare() if shouldRecomputeCommit { - noopSigner, err := noopsigner.NewNoopSigner(privKey) - require.NoError(t, err) - signature, err := GetSignature(preparedHeader.Header, noopSigner) + signature, err := GetSignature(preparedHeader.Header, privKey) require.NoError(t, err) preparedHeader.Signature = signature } @@ -215,9 +211,7 @@ func testValidateBasic(t *testing.T, untrustedAdj *SignedHeader, privKey crypto. preparedHeader, shouldRecomputeCommit := test.prepare() if shouldRecomputeCommit { - noopSigner, err := noopsigner.NewNoopSigner(privKey) - require.NoError(t, err) - signature, err := GetSignature(preparedHeader.Header, noopSigner) + signature, err := GetSignature(preparedHeader.Header, privKey) require.NoError(t, err) preparedHeader.Signature = signature } diff --git a/types/utils.go b/types/utils.go index 43b8437eb6..41eaa86f12 100644 --- a/types/utils.go +++ b/types/utils.go @@ -9,8 +9,6 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/rollkit/rollkit/pkg/genesis" - "github.com/rollkit/rollkit/pkg/signer" - noopsigner "github.com/rollkit/rollkit/pkg/signer/noop" ) // DefaultSigningKeyType is the key type used by the sequencer signing key @@ -140,7 +138,7 @@ func GetRandomSignedHeader(chainID string) (*SignedHeader, crypto.PrivKey, error // GetRandomSignedHeaderCustom creates a signed header based on the provided HeaderConfig. func GetRandomSignedHeaderCustom(config *HeaderConfig, chainID string) (*SignedHeader, error) { - signer, err := noopsigner.NewNoopSigner(config.PrivKey) + signer, err := NewSigner(config.PrivKey.GetPublic()) if err != nil { return nil, err } @@ -150,18 +148,13 @@ func GetRandomSignedHeaderCustom(config *HeaderConfig, chainID string) (*SignedH Signer: signer, } - signerAddress, err := signer.GetAddress() - if err != nil { - return nil, err - } - signedHeader.Header.BaseHeader.Height = config.Height signedHeader.Header.DataHash = config.DataHash - signedHeader.Header.ProposerAddress = signerAddress - signedHeader.Header.ValidatorHash = signerAddress + signedHeader.Header.ProposerAddress = signer.Address + signedHeader.Header.ValidatorHash = signer.Address signedHeader.Header.BaseHeader.Time = uint64(time.Now().UnixNano()) + (config.Height)*10 - signature, err := GetSignature(signedHeader.Header, signer) + signature, err := GetSignature(signedHeader.Header, config.PrivKey) if err != nil { return nil, err } @@ -177,7 +170,7 @@ func GetRandomNextSignedHeader(signedHeader *SignedHeader, privKey crypto.PrivKe Signer: signedHeader.Signer, } - signature, err := GetSignature(newSignedHeader.Header, signedHeader.Signer) + signature, err := GetSignature(newSignedHeader.Header, privKey) if err != nil { return nil, err } @@ -187,12 +180,7 @@ func GetRandomNextSignedHeader(signedHeader *SignedHeader, privKey crypto.PrivKe // GetFirstSignedHeader creates a 1st signed header for a chain, given a valset and signing key. func GetFirstSignedHeader(privkey crypto.PrivKey, chainID string) (*SignedHeader, error) { - signer, err := noopsigner.NewNoopSigner(privkey) - if err != nil { - return nil, err - } - - signerAddress, err := signer.GetAddress() + signer, err := NewSigner(privkey.GetPublic()) if err != nil { return nil, err } @@ -211,13 +199,13 @@ func GetFirstSignedHeader(privkey crypto.PrivKey, chainID string) (*SignedHeader LastCommitHash: GetRandomBytes(32), DataHash: GetRandomBytes(32), AppHash: make([]byte, 32), - ProposerAddress: signerAddress, + ProposerAddress: signer.Address, } signedHeader := SignedHeader{ Header: header, Signer: signer, } - signature, err := GetSignature(header, signer) + signature, err := GetSignature(header, privkey) if err != nil { return nil, err } @@ -232,12 +220,7 @@ func GetGenesisWithPrivkey(chainID string) (genesis.Genesis, crypto.PrivKey, cry panic(err) } - signer, err := noopsigner.NewNoopSigner(privKey) - if err != nil { - panic(err) - } - - signerAddress, err := signer.GetAddress() + signer, err := NewSigner(privKey.GetPublic()) if err != nil { panic(err) } @@ -246,7 +229,7 @@ func GetGenesisWithPrivkey(chainID string) (genesis.Genesis, crypto.PrivKey, cry chainID, 1, time.Now().UTC(), - signerAddress, + signer.Address, nil, ), privKey, pubKey } @@ -268,7 +251,7 @@ func GetRandomBytes(n uint) []byte { } // GetSignature returns a signature from the given private key over the given header -func GetSignature(header Header, proposerKey signer.Signer) (Signature, error) { +func GetSignature(header Header, proposerKey crypto.PrivKey) (Signature, error) { b, err := header.MarshalBinary() if err != nil { return nil, err From 275889001586d7fede66746d122ec444b484c5c4 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 10 Apr 2025 17:10:44 +0200 Subject: [PATCH 4/5] lint --- pkg/store/store_test.go | 1 - types/serialization.go | 2 -- types/signed_header.go | 1 - types/signer.go | 41 +++++++++++++++++++++++++++++++++++++++++ types/utils.go | 2 -- 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 types/signer.go diff --git a/pkg/store/store_test.go b/pkg/store/store_test.go index def03eee14..48b39958d8 100644 --- a/pkg/store/store_test.go +++ b/pkg/store/store_test.go @@ -111,7 +111,6 @@ func TestStoreLoad(t *testing.T) { assert.NoError(err) assert.NotNil(header) assert.NotNil(data) - assert.Equal(expectedHeader, header) assert.Equal(expectedData, data) diff --git a/types/serialization.go b/types/serialization.go index 746488c07b..4f5c6198bd 100644 --- a/types/serialization.go +++ b/types/serialization.go @@ -70,7 +70,6 @@ func (sh *SignedHeader) ToProto() (*pb.SignedHeader, error) { if err != nil { return nil, err } - return &pb.SignedHeader{ Header: sh.Header.ToProto(), Signature: sh.Signature[:], @@ -95,7 +94,6 @@ func (sh *SignedHeader) FromProto(other *pb.SignedHeader) error { if err != nil { return err } - sh.Signer = Signer{ Address: other.Signer.Address, PubKey: pubKey, diff --git a/types/signed_header.go b/types/signed_header.go index 15c62f9085..c3cb862442 100644 --- a/types/signed_header.go +++ b/types/signed_header.go @@ -118,7 +118,6 @@ func (sh *SignedHeader) ValidateBasic() error { if !verified { return ErrSignatureVerificationFailed } - return nil } diff --git a/types/signer.go b/types/signer.go new file mode 100644 index 0000000000..af8498a75f --- /dev/null +++ b/types/signer.go @@ -0,0 +1,41 @@ +package types + +import ( + "crypto/sha256" + + "github.com/libp2p/go-libp2p/core/crypto" +) + +// Signer is a type that can verify messages. +type Signer struct { + PubKey crypto.PubKey + Address []byte +} + +// NewSigner creates a new signer from a public key. +func NewSigner(pubKey crypto.PubKey) (Signer, error) { + bz, err := pubKey.Raw() + if err != nil { + return Signer{}, err + } + + address := sha256.Sum256(bz) + return Signer{ + PubKey: pubKey, + Address: address[:], + }, nil +} + +// Verify verifies a vote with a signature. +func (s *Signer) Verify(vote []byte, signature []byte) (bool, error) { + return s.PubKey.Verify(vote, signature) +} + +func KeyAddress(pubKey crypto.PubKey) []byte { + bz, err := pubKey.Raw() + if err != nil { + return nil + } + hash := sha256.Sum256(bz) + return hash[:] +} diff --git a/types/utils.go b/types/utils.go index 41eaa86f12..08a4f30d51 100644 --- a/types/utils.go +++ b/types/utils.go @@ -147,7 +147,6 @@ func GetRandomSignedHeaderCustom(config *HeaderConfig, chainID string) (*SignedH Header: GetRandomHeader(chainID), Signer: signer, } - signedHeader.Header.BaseHeader.Height = config.Height signedHeader.Header.DataHash = config.DataHash signedHeader.Header.ProposerAddress = signer.Address @@ -184,7 +183,6 @@ func GetFirstSignedHeader(privkey crypto.PrivKey, chainID string) (*SignedHeader if err != nil { return nil, err } - header := Header{ BaseHeader: BaseHeader{ Height: 1, From 3cac8a34074c0bb5a0817c71c19203787a35b892 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 10 Apr 2025 17:31:26 +0200 Subject: [PATCH 5/5] slightly better error handling --- block/manager.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/block/manager.go b/block/manager.go index fd5c9d4f59..511111cf1b 100644 --- a/block/manager.go +++ b/block/manager.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "strings" "sync" "sync/atomic" "time" @@ -998,7 +999,7 @@ func (m *Manager) RetrieveLoop(ctx context.Context) { err := m.processNextDAHeader(ctx) if err != nil && ctx.Err() == nil { // if the requested da height is not yet available, wait silently, otherwise log the error and wait - if !errors.Is(err, ErrHeightFromFutureStr) { + if !m.areAllErrorsHeightFromFuture(err) { m.logger.Error("failed to retrieve block from DALC", "daHeight", daHeight, "errors", err.Error()) } continue @@ -1100,6 +1101,30 @@ func (m *Manager) isUsingExpectedCentralizedSequencer(header *types.SignedHeader return bytes.Equal(header.ProposerAddress, m.genesis.ProposerAddress) && header.ValidateBasic() == nil } +// areAllErrorsHeightFromFuture checks if all errors in a joined error are ErrHeightFromFutureStr +func (m *Manager) areAllErrorsHeightFromFuture(err error) bool { + if err == nil { + return false + } + + // Check if the error itself is ErrHeightFromFutureStr + if strings.Contains(err.Error(), ErrHeightFromFutureStr.Error()) { + return true + } + + // If it's a joined error, check each error recursively + if joinedErr, ok := err.(interface{ Unwrap() []error }); ok { + for _, e := range joinedErr.Unwrap() { + if !m.areAllErrorsHeightFromFuture(e) { + return false + } + } + return true + } + + return false +} + func (m *Manager) fetchHeaders(ctx context.Context, daHeight uint64) (coreda.ResultRetrieve, error) { var err error ctx, cancel := context.WithTimeout(ctx, 60*time.Second) //TODO: make this configurable