-
Notifications
You must be signed in to change notification settings - Fork 968
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(state): Verify the state inclusion proof without splitting keys (#…
…1483) ## Overview There has to be better way of fixing this, but I'm unsure of how we want to handle it, so submitting this for now. The bug is that, when verifying state inclusion proofs, tendermint will perform [some processing](https://github.com/celestiaorg/celestia-core/blob/a0ccbd068927b638705f63acdf6303d3091da985/crypto/merkle/proof_key_path.go#L85-L110) on the keypath that you give it that the sdk simply doesn't have to do. The iavl doesn't do this, as we just pass it the key it wants, not the path. It just sticks the key that you give in the [request right back](https://github.com/cosmos/cosmos-sdk/blob/b46d83850270b82496e4cd61421d9ebc8bac87f2/store/iavl/store.go#L324-L326), and because the processing in tendermint sometimes results in a different key, the proof verification [fails](https://github.com/celestiaorg/celestia-core/blob/a0ccbd068927b638705f63acdf6303d3091da985/crypto/merkle/proof_op.go#L52). Specifically, the string encoding of the bytes we pass it sometimes have the string `/` and `%` in them from the address, the processing tendermint does thinks its supposed to do something when it actually isn't, and then the correct key returned by the sdk no longer matches. This is why we're only seeing some addresses break! [bad processing point 1](https://github.com/celestiaorg/celestia-core/blob/a0ccbd068927b638705f63acdf6303d3091da985/crypto/merkle/proof_key_path.go#L91) [bad processing point 2](https://github.com/celestiaorg/celestia-core/blob/a0ccbd068927b638705f63acdf6303d3091da985/crypto/merkle/proof_key_path.go#L102) (idek why this is there) My quick and dirty solution was to copy paste fork ~~the file from tendermint~~ a few methods that verify proofs, then change the api so we don't have to split the string 😆 . We should fix it properly soon. This might be a bug with tendermint, but I was admittedly too tired to look into it or write up an issue. We might just need to pass a different formatted string(?) as a bonus, I added the foundation for an integration test for the core accessor, that should make it waaaaaaaayyyy easier to round trip test things! 🙂 🎄 pls feel to edit this PR and add whatever else is needed to get this across the finish line closes #1461 ## Checklist - [x] New and updated code has appropriate documentation - [x] New and updated code has new and/or updated testing - [x] Required CI checks are passing - [x] Visual proof for any user facing features like CLI or documentation updates - [x] Linked issues closed with keywords Co-authored-by: rene <[email protected]>
- Loading branch information
1 parent
4734aac
commit 4c5d247
Showing
4 changed files
with
151 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package state | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
"github.com/stretchr/testify/require" | ||
"github.com/stretchr/testify/suite" | ||
tmrand "github.com/tendermint/tendermint/libs/rand" | ||
rpcclient "github.com/tendermint/tendermint/rpc/client" | ||
"google.golang.org/grpc" | ||
|
||
"github.com/celestiaorg/celestia-app/app" | ||
"github.com/celestiaorg/celestia-app/testutil/testnode" | ||
blobtypes "github.com/celestiaorg/celestia-app/x/payment/types" | ||
|
||
"github.com/celestiaorg/celestia-node/header" | ||
) | ||
|
||
func TestIntegrationTestSuite(t *testing.T) { | ||
suite.Run(t, new(IntegrationTestSuite)) | ||
} | ||
|
||
type IntegrationTestSuite struct { | ||
suite.Suite | ||
|
||
cleanups []func() error | ||
accounts []string | ||
cctx testnode.Context | ||
|
||
accessor *CoreAccessor | ||
} | ||
|
||
func (s *IntegrationTestSuite) SetupSuite() { | ||
if testing.Short() { | ||
s.T().Skip("skipping test in unit-tests or race-detector mode.") | ||
} | ||
|
||
s.T().Log("setting up integration test suite") | ||
require := s.Require() | ||
|
||
// we create an arbitrary number of funded accounts | ||
for i := 0; i < 25; i++ { | ||
s.accounts = append(s.accounts, tmrand.Str(9)) | ||
} | ||
|
||
tmNode, app, cctx, err := testnode.New( | ||
s.T(), | ||
testnode.DefaultParams(), | ||
testnode.DefaultTendermintConfig(), | ||
false, | ||
s.accounts..., | ||
) | ||
require.NoError(err) | ||
|
||
cctx, stopNode, err := testnode.StartNode(tmNode, cctx) | ||
require.NoError(err) | ||
s.cleanups = append(s.cleanups, stopNode) | ||
|
||
cctx, cleanupGRPC, err := testnode.StartGRPCServer(app, testnode.DefaultAppConfig(), cctx) | ||
require.NoError(err) | ||
s.cleanups = append(s.cleanups, cleanupGRPC) | ||
|
||
s.cctx = cctx | ||
require.NoError(cctx.WaitForNextBlock()) | ||
|
||
signer := blobtypes.NewKeyringSigner(s.cctx.Keyring, s.accounts[0], cctx.ChainID) | ||
|
||
accessor := NewCoreAccessor(signer, localHeader{s.cctx.Client}, "", "", "") | ||
setClients(accessor, s.cctx.GRPCClient, s.cctx.Client) | ||
s.accessor = accessor | ||
} | ||
|
||
func setClients(ca *CoreAccessor, conn *grpc.ClientConn, abciCli rpcclient.ABCIClient) { | ||
ca.coreConn = conn | ||
// create the query client | ||
queryCli := banktypes.NewQueryClient(ca.coreConn) | ||
ca.queryCli = queryCli | ||
// create the staking query client | ||
stakingCli := stakingtypes.NewQueryClient(ca.coreConn) | ||
ca.stakingCli = stakingCli | ||
|
||
ca.rpcCli = abciCli | ||
} | ||
|
||
func (s *IntegrationTestSuite) TearDownSuite() { | ||
s.T().Log("tearing down integration test suite") | ||
require := s.Require() | ||
require.NoError(s.accessor.Stop(s.cctx.GoContext())) | ||
for _, c := range s.cleanups { | ||
err := c() | ||
require.NoError(err) | ||
} | ||
} | ||
|
||
func (s *IntegrationTestSuite) getAddress(acc string) sdk.Address { | ||
rec, err := s.cctx.Keyring.Key(acc) | ||
require.NoError(s.T(), err) | ||
|
||
addr, err := rec.GetAddress() | ||
require.NoError(s.T(), err) | ||
|
||
return addr | ||
} | ||
|
||
type localHeader struct { | ||
client rpcclient.Client | ||
} | ||
|
||
func (l localHeader) Head(ctx context.Context) (*header.ExtendedHeader, error) { | ||
latest, err := l.client.Block(ctx, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
h := &header.ExtendedHeader{ | ||
RawHeader: latest.Block.Header, | ||
} | ||
return h, nil | ||
} | ||
|
||
func (s *IntegrationTestSuite) TestGetBalance() { | ||
require := s.Require() | ||
expectedBal := sdk.NewCoin(app.BondDenom, sdk.NewInt(int64(99999999999999999))) | ||
for _, acc := range s.accounts { | ||
bal, err := s.accessor.BalanceForAddress(context.Background(), s.getAddress(acc)) | ||
require.NoError(err) | ||
require.Equal(&expectedBal, bal) | ||
} | ||
} |