-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test: consistent appHash between commits #3513
Changes from 11 commits
91194da
3d65302
65d77c9
a3ca919
60861e3
0667101
28c24ff
c0452be
60edfd3
e0d91b2
11e55a2
7b4c1e1
7471b9a
c32926a
ae87db7
92be77f
7512217
d9e3a63
5e49042
8a6523e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package app_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/celestiaorg/celestia-app/v2/app" | ||
"github.com/celestiaorg/celestia-app/v2/app/encoding" | ||
"github.com/celestiaorg/celestia-app/v2/pkg/appconsts" | ||
testutil "github.com/celestiaorg/celestia-app/v2/test/util" | ||
"github.com/celestiaorg/celestia-app/v2/test/util/blobfactory" | ||
"github.com/celestiaorg/celestia-app/v2/test/util/testfactory" | ||
"github.com/celestiaorg/go-square/blob" | ||
appns "github.com/celestiaorg/go-square/namespace" | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
hd "github.com/cosmos/cosmos-sdk/crypto/hd" | ||
keyring "github.com/cosmos/cosmos-sdk/crypto/keyring" | ||
"github.com/cosmos/cosmos-sdk/crypto/types" | ||
"github.com/stretchr/testify/require" | ||
abci "github.com/tendermint/tendermint/abci/types" | ||
) | ||
|
||
// TestNonDeterminismBetweenMainAndV1 executes a set of different transactions, | ||
// produces an app hash and compares it with the app hash produced by v1.x | ||
func TestNonDeterminismBetweenMainAndV1(t *testing.T) { | ||
const ( | ||
numBlobTxs, numNormalTxs = 5, 5 | ||
) | ||
|
||
expectedAppHash := []byte{100, 237, 125, 126, 116, 10, 189, 82, 156, 116, 176, 136, 169, 92, 185, 12, 72, 134, 254, 175, 234, 13, 159, 90, 139, 192, 190, 248, 67, 9, 32, 217} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit][optional since we have this a lot in the repo] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good point i'll link the executable from v1.x in the comments There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll link the file once this pr is merged as a follow-up #3522 |
||
|
||
// Initialize testApp | ||
testApp := testutil.NewTestApp() | ||
|
||
enc := encoding.MakeConfig(app.ModuleEncodingRegisters...) | ||
// Create deterministic keys | ||
kr, pubKeys := DeterministicKeyRing(enc.Codec) | ||
|
||
recs, err := kr.List() | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
require.NoError(t, err) | ||
addresses := make([]string, 0, len(recs)) | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Get the name of the records | ||
for _, rec := range recs { | ||
addresses = append(addresses, rec.Name) | ||
} | ||
|
||
// Apply genesis state to the app | ||
_, _, err = testutil.ApplyGenesisState(testApp, pubKeys, 1_000_000_000, app.DefaultInitialConsensusParams()) | ||
require.NoError(t, err) | ||
|
||
accinfos := queryAccountInfo(testApp, addresses, kr) | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create a set of 10 deterministic sdk transactions | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
normalTxs := testutil.SendTxsWithAccounts( | ||
t, | ||
testApp, | ||
enc.TxConfig, | ||
kr, | ||
1000, | ||
addresses[0], | ||
addresses[:numNormalTxs], | ||
testutil.ChainID, | ||
) | ||
|
||
// Create a set of 5 deterministic blob transactions | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
blobTxs := blobfactory.ManyMultiBlobTx(t, enc.TxConfig, kr, testutil.ChainID, addresses[numBlobTxs+1:], accinfos[numBlobTxs+1:], testfactory.Repeat([]*blob.Blob{ | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
blob.New(DeterministicNamespace(), []byte{1}, appconsts.DefaultShareVersion), | ||
}, numBlobTxs), app.DefaultInitialConsensusParams().Version.AppVersion) | ||
|
||
// Deliver sdk txs | ||
for _, tx := range normalTxs { | ||
resp := testApp.DeliverTx(abci.RequestDeliverTx{Tx: tx}) | ||
require.EqualValues(t, 0, resp.Code, resp.Log) | ||
} | ||
|
||
// Deliver blob txs | ||
for _, tx := range blobTxs { | ||
blobTx, ok := blob.UnmarshalBlobTx(tx) | ||
require.True(t, ok) | ||
resp := testApp.DeliverTx(abci.RequestDeliverTx{Tx: blobTx.Tx}) | ||
require.EqualValues(t, 0, resp.Code, resp.Log) | ||
} | ||
|
||
// Commit the state | ||
testApp.Commit() | ||
|
||
// Get the app hash | ||
appHash := testApp.LastCommitID().Hash | ||
|
||
// Assert that the app hash is equal to the app hash produced by v1.x | ||
require.Equal(t, expectedAppHash, appHash) | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// DeterministicNamespace returns a deterministic namespace | ||
func DeterministicNamespace() appns.Namespace { | ||
return appns.Namespace{ | ||
Version: 0, | ||
ID: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 67, 154, 200, 228, 130, 74, 147, 162, 11}, | ||
} | ||
} | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// DeterministicKeyRing returns a deterministic keyring and a list of deterministic public keys | ||
func DeterministicKeyRing(cdc codec.Codec) (keyring.Keyring, []types.PubKey) { | ||
mnemonics := []string{ | ||
"great myself congress genuine scale muscle view uncover pipe miracle sausage broccoli lonely swap table foam brand turtle comic gorilla firm mad grunt hazard", | ||
"cheap job month trigger flush cactus chest juice dolphin people limit crunch curious secret object beach shield snake hunt group sketch cousin puppy fox", | ||
"oil suffer bamboo one better attack exist dolphin relief enforce cat asset raccoon lava regret found love certain plunge grocery accuse goat together kiss", | ||
"giraffe busy subject doll jump drama sea daring again club spend toe mind organ real liar permit refuse change opinion donkey job cricket speed", | ||
"fee vapor thing fish fan memory negative raven cram win quantum ozone job mirror shoot sting quiz black apart funny sort cancel friend curtain", | ||
"skin beef review pilot tooth act any alarm there only kick uniform ticket material cereal radar ethics list unlock method coral smooth street frequent", | ||
"ecology scout core guard load oil school effort near alcohol fancy save cereal owner enforce impact sand husband trophy solve amount fish festival sell", | ||
"used describe angle twin amateur pyramid bitter pool fluid wing erode rival wife federal curious drink battle put elbow mandate another token reveal tone", | ||
"reason fork target chimney lift typical fine divorce mixture web robot kiwi traffic stove miss crane welcome camp bless fuel october riot pluck ordinary", | ||
"undo logic mobile modify master force donor rose crumble forget plate job canal waste turn damp sure point deposit hazard quantum car annual churn", | ||
"charge subway treat loop donate place loan want grief leg message siren joy road exclude match empty enforce vote meadow enlist vintage wool involve", | ||
} | ||
kb := keyring.NewInMemory(cdc) | ||
ninabarbakadze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pubKeys := make([]types.PubKey, len(mnemonics)) | ||
for idx, mnemonic := range mnemonics { | ||
rec, err := kb.NewAccount(fmt.Sprintf("account-%d", idx), mnemonic, "", "", hd.Secp256k1) | ||
if err != nil { | ||
panic(err) | ||
} | ||
pubKey, err := rec.GetPubKey() | ||
if err != nil { | ||
panic(err) | ||
} | ||
pubKeys[idx] = pubKey | ||
} | ||
return kb, pubKeys | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -222,12 +222,13 @@ func ManyMultiBlobTx( | |
accounts []string, | ||
accInfos []AccountInfo, | ||
blobs [][]*blob.Blob, | ||
appVersion uint64, | ||
) [][]byte { | ||
t.Helper() | ||
txs := make([][]byte, len(accounts)) | ||
opts := DefaultTxOpts() | ||
for i, acc := range accounts { | ||
signer, err := user.NewSigner(kr, enc, chainid, appconsts.LatestVersion, user.NewAccount(acc, accInfos[i].AccountNum, accInfos[i].Sequence)) | ||
signer, err := user.NewSigner(kr, enc, chainid, appVersion, user.NewAccount(acc, accInfos[i].AccountNum, accInfos[i].Sequence)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tip Codebase Verification The verification of the
These instances need to be updated to include the Analysis chainThe addition of the Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify all function calls to `ManyMultiBlobTx` include the `appVersion` parameter.
# Test: Search for the function usage. Expect: Only occurances with the `appVersion` parameter.
rg --type go $'ManyMultiBlobTx'
Length of output: 517 Script: #!/bin/bash
# Extract lines around the calls to ManyMultiBlobTx to verify the presence of the appVersion parameter.
# Extract lines from app/test/process_proposal_test.go
rg --context 5 'ManyMultiBlobTx' app/test/process_proposal_test.go
# Extract lines from app/test/non_determinism_test.go
rg --context 5 'ManyMultiBlobTx' app/test/non_determinism_test.go
# Extract lines from app/test/prepare_proposal_test.go
rg --context 5 'ManyMultiBlobTx' app/test/prepare_proposal_test.go
Length of output: 1920 |
||
require.NoError(t, err) | ||
txs[i], _, err = signer.CreatePayForBlobs(acc, blobs[i], opts...) | ||
require.NoError(t, err) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't necessary be between v1 and main. It should be comparing the app hash generated from this commit compared to the app hash generated from the previous commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree that I think we can rename this function since the commitment should be the same across all branches if I'm understanding this comment correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[optional] slight tangent: the test could be renamed something like
TestConsistentAppHash
because it is asserting some expected app hash matches some calculated app hash. I think the goal is to identify cases of non-determinism but just because this test passes, it doesn't mean we prevented all potential cases of non-determinism.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree with all of your points, i only wanted to underline that the hardcoded apphash was generated on v1.x because technically we could do it between any branches but practically the logic for generating apphash lives on v1.x.