diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 5ae0460f..20ce49f3 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 env: - EVNODE_VERSION: "v1.0.0-beta.2.0.20250818133040-d096a24e7052" + EVNODE_VERSION: "v1.0.0-beta.2.0.20250901092248-017d6d45a621" IGNITE_VERSION: "v29.3.1" IGNITE_EVOLVE_APP_VERSION: "main" # use tagged when apps has tagged (blocked on things) EVOLVE_IMAGE_REPO: "evolve-gm" @@ -59,7 +59,7 @@ jobs: timeout-minutes: 30 env: DO_NOT_TRACK: true - EVNODE_VERSION: "v1.0.0-beta.2.0.20250818133040-d096a24e7052" + EVNODE_VERSION: "v1.0.0-beta.2.0.20250901092248-017d6d45a621" IGNITE_VERSION: "v29.3.1" IGNITE_EVOLVE_APP_VERSION: "main" # use tagged when apps has tagged (blocked on things) outputs: @@ -266,7 +266,7 @@ jobs: GMD_HOME: ${{ needs.liveness.outputs.gmd_home }} HERMES_VERSION: "v1.13.1" GAIA_VERSION: "v25.1.0" - EVNODE_VERSION: "v1.0.0-beta.2.0.20250818133040-d096a24e7052" + EVNODE_VERSION: "v1.0.0-beta.2.0.20250901092248-017d6d45a621" EVNODE_DA_VERSION: "v1.0.0-beta.1" steps: - name: Set up Go diff --git a/.github/workflows/migration_test.yml b/.github/workflows/migration_test.yml index 64f9bee6..db58cc2d 100644 --- a/.github/workflows/migration_test.yml +++ b/.github/workflows/migration_test.yml @@ -13,7 +13,7 @@ jobs: timeout-minutes: 45 env: DO_NOT_TRACK: true - EVNODE_VERSION: "v1.0.0-beta.2.0.20250818133040-d096a24e7052" + EVNODE_VERSION: "v1.0.0-beta.2.0.20250901092248-017d6d45a621" IGNITE_VERSION: "v29.3.1" IGNITE_EVOLVE_APP_VERSION: "main" # use tagged when apps has tagged (blocked on things) steps: diff --git a/Dockerfile b/Dockerfile index 76561fac..0527299b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apk add --no-cache \ bash # Set environment variables -ENV EVNODE_VERSION=v1.0.0-beta.2.0.20250818133040-d096a24e7052 +ENV EVNODE_VERSION=v1.0.0-beta.2.0.20250901092248-017d6d45a621 ENV IGNITE_VERSION=v29.3.1 ENV IGNITE_EVOLVE_APP_VERSION=main diff --git a/go.mod b/go.mod index 9d454de1..e5e4a759 100644 --- a/go.mod +++ b/go.mod @@ -25,10 +25,10 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.14 github.com/cosmos/gogoproto v1.7.0 - github.com/evstack/ev-node v1.0.0-beta.2.0.20250818133040-d096a24e7052 - github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250818133040-d096a24e7052 - github.com/evstack/ev-node/da v0.0.0-20250818133040-d096a24e7052 - github.com/evstack/ev-node/sequencers/single v0.0.0-20250818133040-d096a24e7052 + github.com/evstack/ev-node v1.0.0-beta.2.0.20250901092248-017d6d45a621 + github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250901092248-017d6d45a621 + github.com/evstack/ev-node/da v0.0.0-20250901092248-017d6d45a621 + github.com/evstack/ev-node/sequencers/single v0.0.0-20250901092248-017d6d45a621 github.com/go-kit/kit v0.13.0 github.com/golang/protobuf v1.5.4 github.com/grpc-ecosystem/grpc-gateway v1.16.0 diff --git a/go.sum b/go.sum index d22a5a93..3ac65e2f 100644 --- a/go.sum +++ b/go.sum @@ -290,14 +290,14 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evstack/ev-node v1.0.0-beta.2.0.20250818133040-d096a24e7052 h1:Fsu6gkxsANYfl/AgDEABDN7dmeEXCIcFSPgFKTHZEwA= -github.com/evstack/ev-node v1.0.0-beta.2.0.20250818133040-d096a24e7052/go.mod h1:LEP7bA5MA8+khDuZWmJcg8K8KXQ5jJVLTSETggQbrV0= -github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250818133040-d096a24e7052 h1:FhMa6ZiUSPSq4EeQXAheS6+7vaOSika3eDgSQiTbMJk= -github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250818133040-d096a24e7052/go.mod h1:n2w/LhYQTPsi48m6lMj16YiIqsaQw6gxwjyJvR+B3sY= -github.com/evstack/ev-node/da v0.0.0-20250818133040-d096a24e7052 h1:aHPY3amXzULbIn7M5lslwo3lz9w89gP04wbLNa/k/LI= -github.com/evstack/ev-node/da v0.0.0-20250818133040-d096a24e7052/go.mod h1:ooBV3tAL2o9brFql9I4DKgoDP4BchF3aMrUDR4ARC/k= -github.com/evstack/ev-node/sequencers/single v0.0.0-20250818133040-d096a24e7052 h1:PDM62mPdhXDkOU8RZkBbw7ALKVtXpvgZPYNjfJEwnQc= -github.com/evstack/ev-node/sequencers/single v0.0.0-20250818133040-d096a24e7052/go.mod h1:ll3+DmIF9X5mgyNhT/BaMZBVkS9bPDaq7tWHCqwtdkA= +github.com/evstack/ev-node v1.0.0-beta.2.0.20250901092248-017d6d45a621 h1:c3CM78SnNlQoYqzzYaUTpBAR/FK7JDfS0gd9fTRGe2E= +github.com/evstack/ev-node v1.0.0-beta.2.0.20250901092248-017d6d45a621/go.mod h1:jY/c+EkBt8G8srFBTpKuHrxioLYNLgDn1lFMktITA5Q= +github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250901092248-017d6d45a621 h1:BXfwY70MP9Amivmcs8bWeXZzmOx8dE6Re9jbsKv+YbI= +github.com/evstack/ev-node/core v1.0.0-beta.1.0.20250901092248-017d6d45a621/go.mod h1:n2w/LhYQTPsi48m6lMj16YiIqsaQw6gxwjyJvR+B3sY= +github.com/evstack/ev-node/da v0.0.0-20250901092248-017d6d45a621 h1:nuv0sVhGhjkoF50iKGfi56XwkvlqcKKW1l19MG1Y3LA= +github.com/evstack/ev-node/da v0.0.0-20250901092248-017d6d45a621/go.mod h1:ooBV3tAL2o9brFql9I4DKgoDP4BchF3aMrUDR4ARC/k= +github.com/evstack/ev-node/sequencers/single v0.0.0-20250901092248-017d6d45a621 h1:WvaJVarlm+UQXclO86Fl/xMldJrquIGH6SBR6Fsapng= +github.com/evstack/ev-node/sequencers/single v0.0.0-20250901092248-017d6d45a621/go.mod h1:I9phdwpqEQjkvZVnhf3dvh4wozbiZ2BLY3cwCFxzT08= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go index 4716bd05..2ebed8c3 100644 --- a/pkg/adapter/adapter.go +++ b/pkg/adapter/adapter.go @@ -31,7 +31,6 @@ import ( rstore "github.com/evstack/ev-node/pkg/store" "github.com/evstack/ev-node/types" - "github.com/evstack/ev-abci/pkg/cometcompat" "github.com/evstack/ev-abci/pkg/p2p" execstore "github.com/evstack/ev-abci/pkg/store" ) @@ -326,11 +325,21 @@ func (a *Adapter) ExecuteTxs( return nil, 0, fmt.Errorf("get last commit: %w", err) } - abciHeader, err := cometcompat.ToABCIHeader(header, lastCommit) + abciHeader, err := ToABCIHeader(header, lastCommit) if err != nil { return nil, 0, fmt.Errorf("compute header hash: %w", err) } + cmtTxs := make(cmttypes.Txs, len(txs)) + for i := range txs { + cmtTxs[i] = txs[i] + } + + abciBlock, currentBlockID, err := MakeABCIBlock(blockHeight, cmtTxs, s, abciHeader, lastCommit) + if err != nil { + return nil, 0, err + } + ppResp, err := a.App.ProcessProposal(&abci.RequestProcessProposal{ Hash: abciHeader.Hash(), Height: int64(blockHeight), @@ -448,26 +457,10 @@ func (a *Adapter) ExecuteTxs( if err != nil { return nil, 0, err } - cmtTxs := make(cmttypes.Txs, len(txs)) - for i := range txs { - cmtTxs[i] = txs[i] - } - - abciBlock := s.MakeBlock(int64(blockHeight), cmtTxs, lastCommit, nil, s.Validators.Proposer.Address) - blockParts, err := abciBlock.MakePartSet(cmttypes.BlockPartSizeBytes) - if err != nil { - return nil, 0, fmt.Errorf("make part set: %w", err) - } - - // use abci header hash to match the light client validation check - // where sh.Header.Hash() (comet header) must equal sh.Commit.BlockID.Hash - currentBlockID := cmttypes.BlockID{ - Hash: abciHeader.Hash(), - PartSetHeader: blockParts.Header(), - } + // saving data to ev-abci store - if err := a.Store.SaveBlockID(ctx, blockHeight, ¤tBlockID); err != nil { + if err := a.Store.SaveBlockID(ctx, blockHeight, currentBlockID); err != nil { return nil, 0, fmt.Errorf("save block ID: %w", err) } @@ -497,13 +490,13 @@ func (a *Adapter) ExecuteTxs( func fireEvents( eventBus cmttypes.BlockEventPublisher, block *cmttypes.Block, - blockID cmttypes.BlockID, + blockID *cmttypes.BlockID, abciResponse *abci.ResponseFinalizeBlock, validatorUpdates []*cmttypes.Validator, ) error { if err := eventBus.PublishEventNewBlock(cmttypes.EventDataNewBlock{ Block: block, - BlockID: blockID, + BlockID: *blockID, ResultFinalizeBlock: *abciResponse, }); err != nil { return fmt.Errorf("publish new block event: %w", err) @@ -618,14 +611,14 @@ func cometCommitToABCICommitInfo(commit *cmttypes.Commit) abci.CommitInfo { } type StackedEvent struct { - blockID cmttypes.BlockID + blockID *cmttypes.BlockID block *cmttypes.Block abciResponse *abci.ResponseFinalizeBlock validatorUpdates []*cmttypes.Validator } func (a *Adapter) stackBlockCommitEvents( - blockID cmttypes.BlockID, + blockID *cmttypes.BlockID, block *cmttypes.Block, abciResponse *abci.ResponseFinalizeBlock, validatorUpdates []*cmttypes.Validator, diff --git a/pkg/adapter/adapter_test.go b/pkg/adapter/adapter_test.go index fafd9c29..2904e2fe 100644 --- a/pkg/adapter/adapter_test.go +++ b/pkg/adapter/adapter_test.go @@ -24,7 +24,6 @@ import ( "github.com/evstack/ev-node/types" - "github.com/evstack/ev-abci/pkg/cometcompat" execstore "github.com/evstack/ev-abci/pkg/store" ) @@ -104,7 +103,7 @@ func TestExecuteFiresEvents(t *testing.T) { AppHash: []byte("apphash1"), } - headerBz, err := cometcompat.SignaturePayloadProvider(adapter.Store)(&header) + headerBz, err := AggregatorNodeSignatureBytesProvider(adapter)(&header) require.NoError(t, err) sig, err := privKey.Sign(headerBz) diff --git a/pkg/cometcompat/convert.go b/pkg/adapter/convert.go similarity index 72% rename from pkg/cometcompat/convert.go rename to pkg/adapter/convert.go index a5629006..7210dbe5 100644 --- a/pkg/cometcompat/convert.go +++ b/pkg/adapter/convert.go @@ -1,4 +1,4 @@ -package cometcompat +package adapter import ( "errors" @@ -6,6 +6,7 @@ import ( cmbytes "github.com/cometbft/cometbft/libs/bytes" cmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" + cmtstate "github.com/cometbft/cometbft/state" cmttypes "github.com/cometbft/cometbft/types" cmtversion "github.com/cometbft/cometbft/version" @@ -74,3 +75,34 @@ func ToABCIBlockMeta(abciBlock *cmttypes.Block) (*cmttypes.BlockMeta, error) { NumTxs: len(abciBlock.Txs), }, nil } + +// MakeABCIBlock makes an ABCI block and its block ID. +func MakeABCIBlock( + blockHeight uint64, + cmtTxs cmttypes.Txs, + currentState *cmtstate.State, + abciHeader cmttypes.Header, + lastCommit *cmttypes.Commit, +) (*cmttypes.Block, *cmttypes.BlockID, error) { + abciBlock := currentState.MakeBlock( + int64(blockHeight), + cmtTxs, + lastCommit, + nil, + currentState.Validators.Proposer.Address, + ) + + blockParts, err := abciBlock.MakePartSet(cmttypes.BlockPartSizeBytes) + if err != nil { + return nil, nil, fmt.Errorf("make part set: %w", err) + } + + // use abci header hash to match the light client validation check + // where sh.Header.Hash() (comet header) must equal sh.Commit.BlockID.Hash + currentBlockID := &cmttypes.BlockID{ + Hash: abciHeader.Hash(), + PartSetHeader: blockParts.Header(), + } + + return abciBlock, currentBlockID, nil +} diff --git a/pkg/adapter/providers.go b/pkg/adapter/providers.go new file mode 100644 index 00000000..83b99c33 --- /dev/null +++ b/pkg/adapter/providers.go @@ -0,0 +1,123 @@ +package adapter + +import ( + "bytes" + "context" + stdsha256 "crypto/sha256" + "encoding/hex" + "fmt" + + tmcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/libp2p/go-libp2p/core/crypto" + + evtypes "github.com/evstack/ev-node/types" +) + +func AggregatorNodeSignatureBytesProvider(adapter *Adapter) evtypes.AggregatorNodeSignatureBytesProvider { + return func(header *evtypes.Header) ([]byte, error) { + blockID, err := adapter.Store.GetBlockID(context.Background(), header.Height()) + if err != nil && header.Height() > 1 { + return nil, err + } + + return createVote(header, blockID), nil + } +} + +func SyncNodeSignatureBytesProvider(adapter *Adapter) evtypes.SyncNodeSignatureBytesProvider { + return func(ctx context.Context, header *evtypes.Header, data *evtypes.Data) ([]byte, error) { + blockHeight := header.Height() + blockID := &cmttypes.BlockID{} + + if header.Height() > 1 { // first block has an empty block ID + cmtTxs := make(cmttypes.Txs, len(data.Txs)) + for i := range data.Txs { + cmtTxs[i] = cmttypes.Tx(data.Txs[i]) + } + + lastCommit, err := adapter.GetLastCommit(ctx, blockHeight) + if err != nil { + return nil, fmt.Errorf("get last commit: %w", err) + } + + abciHeader, err := ToABCIHeader(*header, lastCommit) + if err != nil { + return nil, fmt.Errorf("compute header hash: %w", err) + } + + currentState, err := adapter.Store.LoadState(ctx) + if err != nil { + return nil, fmt.Errorf("load state: %w", err) + } + + _, blockID, err = MakeABCIBlock(blockHeight, cmtTxs, currentState, abciHeader, lastCommit) + if err != nil { + return nil, fmt.Errorf("make ABCI block: %w", err) + } + } + + return createVote(header, blockID), nil + } +} + +// createVote builds the vote for the given header and block ID to be signed. +func createVote(header *evtypes.Header, blockID *cmttypes.BlockID) []byte { + vote := cmtproto.Vote{ + Type: cmtproto.PrecommitType, + Height: int64(header.Height()), //nolint:gosec + BlockID: blockID.ToProto(), + Round: 0, + Timestamp: header.Time(), + ValidatorAddress: header.ProposerAddress, + ValidatorIndex: 0, + } + + chainID := header.ChainID() + consensusVoteBytes := cmttypes.VoteSignBytes(chainID, &vote) + + return consensusVoteBytes +} + +// ValidatorHasher returns a function that calculates the ValidatorHash +// compatible with CometBFT. This function is intended to be injected into ev-node's Manager. +func ValidatorHasherProvider() func(proposerAddress []byte, pubKey crypto.PubKey) (evtypes.Hash, error) { + return func(proposerAddress []byte, pubKey crypto.PubKey) (evtypes.Hash, error) { + var calculatedHash evtypes.Hash + + var cometBftPubKey tmcryptoed25519.PubKey + if pubKey.Type() == crypto.Ed25519 { + rawKey, err := pubKey.Raw() + if err != nil { + return calculatedHash, fmt.Errorf("failed to get raw bytes from libp2p public key: %w", err) + } + if len(rawKey) != tmcryptoed25519.PubKeySize { + return calculatedHash, fmt.Errorf("libp2p public key size (%d) does not match CometBFT Ed25519 PubKeySize (%d)", len(rawKey), tmcryptoed25519.PubKeySize) + } + cometBftPubKey = rawKey + } else { + return calculatedHash, fmt.Errorf("unsupported public key type '%s', expected Ed25519 for CometBFT compatibility", pubKey.Type()) + } + + votingPower := int64(1) + sequencerValidator := cmttypes.NewValidator(cometBftPubKey, votingPower) + + derivedAddress := sequencerValidator.Address.Bytes() + if !bytes.Equal(derivedAddress, proposerAddress) { + return calculatedHash, fmt.Errorf("CRITICAL MISMATCH - derived validator address (%s) does not match expected proposer address (%s). PubKey used for derivation: %s", + hex.EncodeToString(derivedAddress), + hex.EncodeToString(proposerAddress), + hex.EncodeToString(cometBftPubKey.Bytes())) + } + + sequencerValidatorSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{sequencerValidator}) + + hashSumBytes := sequencerValidatorSet.Hash() + + calculatedHash = make(evtypes.Hash, stdsha256.Size) + copy(calculatedHash, hashSumBytes) + + return calculatedHash, nil + } +} diff --git a/pkg/adapter/signature_compatibility_test.go b/pkg/adapter/signature_compatibility_test.go new file mode 100644 index 00000000..10a85606 --- /dev/null +++ b/pkg/adapter/signature_compatibility_test.go @@ -0,0 +1,91 @@ +package adapter + +import ( + "context" + "testing" + "time" + + "github.com/cometbft/cometbft/crypto/ed25519" + cmttypes "github.com/cometbft/cometbft/types" + ds "github.com/ipfs/go-datastore" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/stretchr/testify/require" + + "github.com/evstack/ev-node/types" + + "github.com/evstack/ev-abci/pkg/store" +) + +func TestSignatureCompatibility_HeaderAndCommit(t *testing.T) { + // Create test key pair + cmtPrivKey := ed25519.GenPrivKey() + p2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(cmtPrivKey.Bytes()) + require.NoError(t, err) + + // Create a test store + dsStore := ds.NewMapDatastore() + storeOnlyAdapter := NewABCIExecutor(nil, dsStore, nil, nil, nil, nil, nil) + + validatorAddress := make([]byte, 20) + chainID := "test-chain" + + // Create a test header + header := &types.Header{ + BaseHeader: types.BaseHeader{ + Height: 1, + Time: uint64(time.Now().UnixNano()), + ChainID: chainID, + }, + ProposerAddress: validatorAddress, + } + + // Test 1: AggregatorNodeSignatureBytesProvider should work without BlockID in store + provider := AggregatorNodeSignatureBytesProvider(storeOnlyAdapter) + signBytes, err := provider(header) + require.NoError(t, err) + require.NotEmpty(t, signBytes) + + syncProvider := SyncNodeSignatureBytesProvider(storeOnlyAdapter) + signBytesSync, err := syncProvider(context.Background(), header, &types.Data{}) + require.NoError(t, err) + require.NotEmpty(t, signBytesSync) + + require.Equal(t, signBytes, signBytesSync) + + // Test 2: Should be able to sign the payload + signature, err := p2pPrivKey.Sign(signBytes) + require.NoError(t, err) + require.NotEmpty(t, signature) + require.Equal(t, 64, len(signature)) // Ed25519 signature length + + // Test 3: Set up proper state and create consistent BlockID for both providers (at height > 2) + state := store.TestingStateFixture() + state.LastBlockHeight = 2 + err = storeOnlyAdapter.Store.SaveState(context.Background(), store.TestingStateFixture()) + require.NoError(t, err) + + // Create BlockID using the same method that SyncNodeSignatureBytesProvider uses + currentState, err := storeOnlyAdapter.Store.LoadState(context.Background()) + require.NoError(t, err) + + lastCommit, err := storeOnlyAdapter.GetLastCommit(context.Background(), header.Height()) + require.NoError(t, err) + + abciHeader, err := ToABCIHeader(*header, lastCommit) + require.NoError(t, err) + + cmtTxs := make(cmttypes.Txs, 0) + _, blockID, err := MakeABCIBlock(header.Height(), cmtTxs, currentState, abciHeader, lastCommit) + require.NoError(t, err) + + // Save the properly generated BlockID to the store + err = storeOnlyAdapter.Store.SaveBlockID(context.Background(), header.Height(), blockID) + require.NoError(t, err) + + signBytes2, err := provider(header) + require.NoError(t, err) + require.NotEmpty(t, signBytes2) + + // The sign bytes should be different now that we have a real BlockID + require.NotEqual(t, signBytes, signBytes2) +} diff --git a/pkg/cometcompat/signature_compatibility_test.go b/pkg/cometcompat/signature_compatibility_test.go deleted file mode 100644 index b953d632..00000000 --- a/pkg/cometcompat/signature_compatibility_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package cometcompat - -import ( - "context" - "testing" - "time" - - "github.com/cometbft/cometbft/crypto/ed25519" - cmttypes "github.com/cometbft/cometbft/types" - ds "github.com/ipfs/go-datastore" - "github.com/libp2p/go-libp2p/core/crypto" - "github.com/stretchr/testify/require" - - "github.com/evstack/ev-node/types" - - execstore "github.com/evstack/ev-abci/pkg/store" -) - -func TestSignatureCompatibility_HeaderAndCommit(t *testing.T) { - // Create test key pair - cmtPrivKey := ed25519.GenPrivKey() - p2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(cmtPrivKey.Bytes()) - require.NoError(t, err) - - // Create a test store - dsStore := ds.NewMapDatastore() - store := execstore.NewExecABCIStore(dsStore) - - validatorAddress := make([]byte, 20) - chainID := "test-chain" - - // Create a test header - header := &types.Header{ - BaseHeader: types.BaseHeader{ - Height: 1, - Time: uint64(time.Now().UnixNano()), - ChainID: chainID, - }, - ProposerAddress: validatorAddress, - } - - // Test 1: SignaturePayloadProvider should work without BlockID in store - provider := SignaturePayloadProvider(store) - signBytes, err := provider(header) - require.NoError(t, err) - require.NotEmpty(t, signBytes) - - // Test 2: Should be able to sign the payload - signature, err := p2pPrivKey.Sign(signBytes) - require.NoError(t, err) - require.NotEmpty(t, signature) - require.Equal(t, 64, len(signature)) // Ed25519 signature length - - // Test 3: After saving BlockID, should still work - blockID := &cmttypes.BlockID{ - Hash: make([]byte, 32), // dummy hash for test - } - err = store.SaveBlockID(context.Background(), header.Height(), blockID) - require.NoError(t, err) - - signBytes2, err := provider(header) - require.NoError(t, err) - require.NotEmpty(t, signBytes2) - - // The sign bytes should be different now that we have a real BlockID - require.NotEqual(t, signBytes, signBytes2) -} diff --git a/pkg/cometcompat/signer.go b/pkg/cometcompat/signer.go deleted file mode 100644 index b52f3811..00000000 --- a/pkg/cometcompat/signer.go +++ /dev/null @@ -1,36 +0,0 @@ -package cometcompat - -import ( - "context" - - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - cmttypes "github.com/cometbft/cometbft/types" - - "github.com/evstack/ev-node/types" - - abciexecstore "github.com/evstack/ev-abci/pkg/store" -) - -func SignaturePayloadProvider(store *abciexecstore.Store) types.SignaturePayloadProvider { - return func(header *types.Header) ([]byte, error) { - blockID, err := store.GetBlockID(context.Background(), header.Height()) - if err != nil && header.Height() > 1 { - return nil, err - } - - vote := cmtproto.Vote{ - Type: cmtproto.PrecommitType, - Height: int64(header.Height()), //nolint:gosec - BlockID: blockID.ToProto(), - Round: 0, - Timestamp: header.Time(), - ValidatorAddress: header.ProposerAddress, - ValidatorIndex: 0, - } - - chainID := header.ChainID() - consensusVoteBytes := cmttypes.VoteSignBytes(chainID, &vote) - - return consensusVoteBytes, nil - } -} diff --git a/pkg/cometcompat/validator_hasher.go b/pkg/cometcompat/validator_hasher.go deleted file mode 100644 index 89f8a14b..00000000 --- a/pkg/cometcompat/validator_hasher.go +++ /dev/null @@ -1,56 +0,0 @@ -package cometcompat - -import ( - "bytes" - stdsha256 "crypto/sha256" - "encoding/hex" - "fmt" - - tmcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" - tmtypes "github.com/cometbft/cometbft/types" - "github.com/libp2p/go-libp2p/core/crypto" - - rollkittypes "github.com/evstack/ev-node/types" -) - -// ValidatorHasher returns a function that calculates the ValidatorHash -// compatible with CometBFT. This function is intended to be injected into ev-node's Manager. -func ValidatorHasherProvider() func(proposerAddress []byte, pubKey crypto.PubKey) (rollkittypes.Hash, error) { - return func(proposerAddress []byte, pubKey crypto.PubKey) (rollkittypes.Hash, error) { - var calculatedHash rollkittypes.Hash - - var cometBftPubKey tmcryptoed25519.PubKey - if pubKey.Type() == crypto.Ed25519 { - rawKey, err := pubKey.Raw() - if err != nil { - return calculatedHash, fmt.Errorf("failed to get raw bytes from libp2p public key: %w", err) - } - if len(rawKey) != tmcryptoed25519.PubKeySize { - return calculatedHash, fmt.Errorf("libp2p public key size (%d) does not match CometBFT Ed25519 PubKeySize (%d)", len(rawKey), tmcryptoed25519.PubKeySize) - } - cometBftPubKey = rawKey - } else { - return calculatedHash, fmt.Errorf("unsupported public key type '%s', expected Ed25519 for CometBFT compatibility", pubKey.Type()) - } - - votingPower := int64(1) - sequencerValidator := tmtypes.NewValidator(cometBftPubKey, votingPower) - - derivedAddress := sequencerValidator.Address.Bytes() - if !bytes.Equal(derivedAddress, proposerAddress) { - return calculatedHash, fmt.Errorf("CRITICAL MISMATCH - derived validator address (%s) does not match expected proposer address (%s). PubKey used for derivation: %s", - hex.EncodeToString(derivedAddress), - hex.EncodeToString(proposerAddress), - hex.EncodeToString(cometBftPubKey.Bytes())) - } - - sequencerValidatorSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{sequencerValidator}) - - hashSumBytes := sequencerValidatorSet.Hash() - - calculatedHash = make(rollkittypes.Hash, stdsha256.Size) - copy(calculatedHash, hashSumBytes) - - return calculatedHash, nil - } -} diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index a53a651b..2e5b87fd 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -15,7 +15,7 @@ import ( storepkg "github.com/evstack/ev-node/pkg/store" rlktypes "github.com/evstack/ev-node/types" - "github.com/evstack/ev-abci/pkg/cometcompat" + "github.com/evstack/ev-abci/pkg/adapter" ) // BlockSearch searches for a paginated set of blocks matching BeginBlock and @@ -77,12 +77,12 @@ func BlockSearch( return nil, fmt.Errorf("failed to get last commit for block %d: %w", results[i], err) } - abciHeader, err := cometcompat.ToABCIHeader(header.Header, lastCommit) + abciHeader, err := adapter.ToABCIHeader(header.Header, lastCommit) if err != nil { return nil, fmt.Errorf("failed to convert header to ABCI format: %w", err) } - abciBlock, err := cometcompat.ToABCIBlock(abciHeader, lastCommit, data) + abciBlock, err := adapter.ToABCIBlock(abciHeader, lastCommit, data) if err != nil { return nil, err } @@ -162,12 +162,12 @@ func BlockByHash(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error return nil, fmt.Errorf("failed to get last commit for block %d: %w", header.Height(), err) } - abciHeader, err := cometcompat.ToABCIHeader(header.Header, lastCommit) + abciHeader, err := adapter.ToABCIHeader(header.Header, lastCommit) if err != nil { return nil, fmt.Errorf("failed to convert header to ABCI format: %w", err) } - abciBlock, err := cometcompat.ToABCIBlock(abciHeader, lastCommit, data) + abciBlock, err := adapter.ToABCIBlock(abciHeader, lastCommit, data) if err != nil { return nil, err } @@ -267,7 +267,7 @@ func HeaderByHash(ctx *rpctypes.Context, hash cmbytes.HexBytes) (*ctypes.ResultH return nil, fmt.Errorf("failed to get last commit for block %d: %w", header.Height(), err) } - abciHeader, err := cometcompat.ToABCIHeader(header.Header, lastCommit) + abciHeader, err := adapter.ToABCIHeader(header.Header, lastCommit) if err != nil { return nil, fmt.Errorf("failed to convert header to ABCI format: %w", err) } diff --git a/pkg/rpc/core/blocks_test.go b/pkg/rpc/core/blocks_test.go index c825b4d2..f41fe95c 100644 --- a/pkg/rpc/core/blocks_test.go +++ b/pkg/rpc/core/blocks_test.go @@ -21,7 +21,6 @@ import ( "github.com/evstack/ev-node/types" "github.com/evstack/ev-abci/pkg/adapter" - "github.com/evstack/ev-abci/pkg/cometcompat" execstore "github.com/evstack/ev-abci/pkg/store" ) @@ -201,8 +200,8 @@ func TestCommit_VerifyCometBFTLightClientCompatibility_MultipleBlocks(t *testing chainID := "test-chain" now := time.Now() - // use the validator hasher helper from cometcompat - validatorHash, err := cometcompat.ValidatorHasherProvider()(validatorAddress, aggregatorPubKey) + // use the validator hasher helpers + validatorHash, err := adapter.ValidatorHasherProvider()(validatorAddress, aggregatorPubKey) require.NoError(err) fixedValSet := &cmttypes.ValidatorSet{ @@ -222,10 +221,10 @@ func TestCommit_VerifyCometBFTLightClientCompatibility_MultipleBlocks(t *testing lastCommit, err := env.Adapter.GetLastCommit(context.Background(), blockHeight) require.NoError(err, "Failed to get last commit for height %d", blockHeight) - abciHeader, err := cometcompat.ToABCIHeader(rollkitHeader, lastCommit) + abciHeader, err := adapter.ToABCIHeader(rollkitHeader, lastCommit) require.NoError(err, "Failed to create ABCI header") - abciBlock, err := cometcompat.ToABCIBlock(abciHeader, lastCommit, blockData) + abciBlock, err := adapter.ToABCIBlock(abciHeader, lastCommit, blockData) require.NoError(err, "Failed to create ABCI block") blockParts, err := abciBlock.MakePartSet(cmttypes.BlockPartSizeBytes) @@ -241,7 +240,7 @@ func TestCommit_VerifyCometBFTLightClientCompatibility_MultipleBlocks(t *testing require.NoError(err, "Failed to save BlockID for height %d", blockHeight) // create the signature for the rollkit block - realSignature := signBlock(t, env.Adapter.Store, rollkitHeader, aggregatorPrivKey) + realSignature := signBlock(t, env.Adapter, rollkitHeader, aggregatorPrivKey) // mock the store to return our signed block mockBlock(blockHeight, rollkitHeader, blockData, realSignature, aggregatorPubKey, validatorAddress) @@ -288,8 +287,8 @@ func createTestBlock(height uint64, chainID string, baseTime time.Time, validato return blockData, rollkitHeader } -func signBlock(t *testing.T, abciExecStore *execstore.Store, header types.Header, privKey crypto.PrivKey) []byte { - signBytes, err := cometcompat.SignaturePayloadProvider(abciExecStore)(&header) +func signBlock(t *testing.T, executor *adapter.Adapter, header types.Header, privKey crypto.PrivKey) []byte { + signBytes, err := adapter.AggregatorNodeSignatureBytesProvider(executor)(&header) require.NoError(t, err) signature, err := privKey.Sign(signBytes) diff --git a/pkg/rpc/core/utils.go b/pkg/rpc/core/utils.go index 470eca1f..6129ba7b 100644 --- a/pkg/rpc/core/utils.go +++ b/pkg/rpc/core/utils.go @@ -8,7 +8,7 @@ import ( cmttypes "github.com/cometbft/cometbft/types" - "github.com/evstack/ev-abci/pkg/cometcompat" + "github.com/evstack/ev-abci/pkg/adapter" ) const NodeIDByteLength = 20 @@ -51,19 +51,19 @@ func getBlockMeta(ctx context.Context, n uint64) (*cmttypes.BlockMeta, *cmttypes return nil, nil } - abciHeader, err := cometcompat.ToABCIHeader(header.Header, lastCommit) + abciHeader, err := adapter.ToABCIHeader(header.Header, lastCommit) if err != nil { env.Logger.Error("Failed to convert header to ABCI format", "height", n, "err", err) return nil, nil } - abciBlock, err := cometcompat.ToABCIBlock(abciHeader, lastCommit, data) + abciBlock, err := adapter.ToABCIBlock(abciHeader, lastCommit, data) if err != nil { env.Logger.Error("Failed to convert block to ABCI format", "height", n, "err", err) return nil, nil } - abciBlockMeta, err := cometcompat.ToABCIBlockMeta(abciBlock) + abciBlockMeta, err := adapter.ToABCIBlockMeta(abciBlock) if err != nil { env.Logger.Error("Failed to convert block to ABCI block meta", "height", n, "err", err) return nil, nil diff --git a/server/migration_cmd_test.go b/server/migration_cmd_test.go index ae5a9af3..18535048 100644 --- a/server/migration_cmd_test.go +++ b/server/migration_cmd_test.go @@ -242,7 +242,7 @@ func TestRollkitMigrationGenesis(t *testing.T) { require.NotNil(t, rollkitGenesis) require.Equal(t, chainID, rollkitGenesis.ChainID) require.Equal(t, uint64(initialHeight), rollkitGenesis.InitialHeight) - require.Equal(t, time.Unix(0, blockTime.UnixNano()), rollkitGenesis.GenesisDAStartTime) + require.Equal(t, time.Unix(0, blockTime.UnixNano()), rollkitGenesis.StartTime) require.Equal(t, address.Bytes(), rollkitGenesis.ProposerAddress) // verify validator set contains the expected validator diff --git a/server/start.go b/server/start.go index e776e579..e84beb01 100644 --- a/server/start.go +++ b/server/start.go @@ -50,11 +50,9 @@ import ( "github.com/evstack/ev-node/sequencers/single" "github.com/evstack/ev-abci/pkg/adapter" - "github.com/evstack/ev-abci/pkg/cometcompat" "github.com/evstack/ev-abci/pkg/rpc" "github.com/evstack/ev-abci/pkg/rpc/core" execsigner "github.com/evstack/ev-abci/pkg/signer" - execstore "github.com/evstack/ev-abci/pkg/store" ) const ( @@ -359,7 +357,7 @@ func setupNodeAndExecutor( appGenesis = &genutiltypes.AppGenesis{ ChainID: migrationGenesis.ChainID, InitialHeight: int64(migrationGenesis.InitialHeight), - GenesisTime: rollkitGenesis.GenesisDAStartTime, + GenesisTime: rollkitGenesis.StartTime, Consensus: &genutiltypes.ConsensusGenesis{ // used in rpc/status.go Validators: []cmttypes.GenesisValidator{ { @@ -495,8 +493,9 @@ func setupNodeAndExecutor( *evLogger, node.NodeOptions{ ManagerOptions: rollkitblock.ManagerOptions{ - SignaturePayloadProvider: cometcompat.SignaturePayloadProvider(execstore.NewExecABCIStore(database)), - ValidatorHasherProvider: cometcompat.ValidatorHasherProvider(), + AggregatorNodeSignatureBytesProvider: adapter.AggregatorNodeSignatureBytesProvider(executor), + SyncNodeSignatureBytesProvider: adapter.SyncNodeSignatureBytesProvider(executor), + ValidatorHasherProvider: adapter.ValidatorHasherProvider(), }, }, )