From a1b8ac2bb792fbcfcf2db3a533237db24451112d Mon Sep 17 00:00:00 2001 From: Silas Davis Date: Tue, 23 Mar 2021 13:42:32 +0100 Subject: [PATCH] Fix unstable genesis hash between v0.30.0 and v0.31.0 This was due to accidental removaal of `omitempty` from AppHash. Also: - Add simple genesis stability snapshot test - Treat `GenesisDoc.ChainID` as read only and re-introduce `GenesisDoc.chainID` as lazy memo storage for ChainID to avoid writing back a chainID which was generated and never present in verbatim gendoc Signed-off-by: Silas Davis --- bcm/blockchain_test.go | 2 +- execution/evm/abi/abi.go | 2 +- genesis/genesis.go | 24 +++++--- genesis/genesis_test.go | 127 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 11 deletions(-) diff --git a/bcm/blockchain_test.go b/bcm/blockchain_test.go index ea93d2ad4..fdf10cf71 100644 --- a/bcm/blockchain_test.go +++ b/bcm/blockchain_test.go @@ -21,7 +21,7 @@ func TestLoadOrNewBlockchain(t *testing.T) { assert.False(t, exists) assert.Equal(t, genesisDoc.GenesisTime, blockchain.LastBlockTime()) assert.Equal(t, uint64(0), blockchain.LastBlockHeight()) - assert.Equal(t, genesisDoc.Hash(), blockchain.AppHashAfterLastBlock()) + assert.Equal(t, genesisDoc.Hash().Bytes(), blockchain.AppHashAfterLastBlock()) // First block blockTime1 := genesisDoc.GenesisTime.Add(time.Second * 10) diff --git a/execution/evm/abi/abi.go b/execution/evm/abi/abi.go index 84fab5c59..79244b2b4 100644 --- a/execution/evm/abi/abi.go +++ b/execution/evm/abi/abi.go @@ -35,7 +35,7 @@ func LoadPath(abiFileOrDirs ...string) (*Spec, error) { return fmt.Errorf("error returned while walking abiDir '%s': %v", dir, err) } ext := filepath.Ext(path) - if fi.IsDir() || !(ext == ".bin" || ext == ".abi") { + if fi.IsDir() || !(ext == ".bin" || ext == ".abi" || ext == ".json") { return nil } abiSpc, err := ReadSpecFile(path) diff --git a/genesis/genesis.go b/genesis/genesis.go index 387d78c7e..70e0fb2ba 100644 --- a/genesis/genesis.go +++ b/genesis/genesis.go @@ -57,15 +57,16 @@ type GenesisDoc struct { GenesisTime time.Time ChainName string // Ordinarily we derive this from the genesis hash but to support explicit Ethereum ChainID it may be set - ChainID string `json:",omitempty" toml:",omitempty"` - AppHash binary.HexBytes - Params params `json:",omitempty" toml:",omitempty"` - Salt []byte `json:",omitempty" toml:",omitempty"` + ChainID string `json:",omitempty" toml:",omitempty"` + AppHash binary.HexBytes `json:",omitempty" toml:",omitempty"` + Params params `json:",omitempty" toml:",omitempty"` + Salt []byte `json:",omitempty" toml:",omitempty"` GlobalPermissions permission.AccountPermissions Accounts []Account Validators []Validator // memo - hash []byte + chainID string + hash []byte } func (genesisDoc *GenesisDoc) GlobalPermissionsAccount() *acm.Account { @@ -98,7 +99,7 @@ func (genesisDoc *GenesisDoc) JSONBytes() ([]byte, error) { return json.MarshalIndent(genesisDoc, "", "\t") } -func (genesisDoc *GenesisDoc) Hash() []byte { +func (genesisDoc *GenesisDoc) Hash() binary.HexBytes { if genesisDoc.hash != nil { return genesisDoc.hash } @@ -117,10 +118,15 @@ func (genesisDoc *GenesisDoc) ShortHash() []byte { } func (genesisDoc *GenesisDoc) GetChainID() string { - if genesisDoc.ChainID == "" { - genesisDoc.ChainID = fmt.Sprintf("%s-%X", genesisDoc.ChainName, genesisDoc.ShortHash()) + if genesisDoc.chainID == "" { + // Prefer explicit override ChainID + if genesisDoc.ChainID != "" { + genesisDoc.chainID = genesisDoc.ChainID + } else { + genesisDoc.chainID = fmt.Sprintf("%s-%X", genesisDoc.ChainName, genesisDoc.ShortHash()) + } } - return genesisDoc.ChainID + return genesisDoc.chainID } //------------------------------------------------------------ diff --git a/genesis/genesis_test.go b/genesis/genesis_test.go index 1229a00e2..095febbc6 100644 --- a/genesis/genesis_test.go +++ b/genesis/genesis_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/hyperledger/burrow/acm" "github.com/hyperledger/burrow/acm/validator" "github.com/hyperledger/burrow/permission" @@ -33,6 +35,16 @@ func TestMakeGenesisDocFromAccounts(t *testing.T) { assert.Equal(t, genDoc.Hash(), genDocOut.Hash()) fmt.Println(string(bs)) } +func TestGenesisStability(t *testing.T) { + genDoc := MakeGenesisDocFromAccounts("test-chain", nil, genesisTime, + accountMap("Tinkie-winkie", "Lala", "Po", "Dipsy"), + validatorMap("Foo", "Bar", "Baz"), + ) + + require.Equal(t, expectedGenesisJSON, genDoc.JSONString()) + + require.Equal(t, "C5B64E6AD231221C328271ADCE401AA11F9DF12830F7DA2FC3B2C923E929C532", genDoc.Hash().String()) +} func accountMap(names ...string) map[string]*acm.Account { accounts := make(map[string]*acm.Account, len(names)) @@ -59,3 +71,118 @@ func accountFromName(name string) *acm.Account { ca.Permissions = permission.AllAccountPermissions.Clone() return ca } + +// For genesis stability test +const expectedGenesisJSON = `{ + "GenesisTime": "2017-10-27T00:00:00Z", + "ChainName": "test-chain", + "Params": { + "ProposalThreshold": 0 + }, + "GlobalPermissions": { + "Base": { + "Perms": "send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | hasRole", + "SetBit": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole" + } + }, + "Accounts": [ + { + "Address": "410427F4A361B958C97B47D81DAFDCF0A2B6503D", + "PublicKey": null, + "Amount": 521, + "Name": "Dipsy", + "Permissions": { + "Base": { + "Perms": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole", + "SetBit": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole" + } + } + }, + { + "Address": "1815E3667F406CA3872234D2573014CDE6CD2ABC", + "PublicKey": null, + "Amount": 378, + "Name": "Lala", + "Permissions": { + "Base": { + "Perms": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole", + "SetBit": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole" + } + } + }, + { + "Address": "A8174022832E4BA1BB52B380128514F72FB2FEBD", + "PublicKey": null, + "Amount": 191, + "Name": "Po", + "Permissions": { + "Base": { + "Perms": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole", + "SetBit": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole" + } + } + }, + { + "Address": "8979C634DFD2F6D20975EBE02C34B5E9C280AB18", + "PublicKey": null, + "Amount": 1304, + "Name": "Tinkie-winkie", + "Permissions": { + "Base": { + "Perms": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole", + "SetBit": "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole" + } + } + } + ], + "Validators": [ + { + "Address": "29BB63AD75E2DA3368FC823DC68C01CF1FA87190", + "PublicKey": { + "CurveType": "ed25519", + "PublicKey": "A18679ADC4391630178AC0DB35A115BEAEDA38B3DEABF92AC5FDE31A748DC259" + }, + "Amount": 277, + "Name": "Bar", + "UnbondTo": [ + { + "Address": "29BB63AD75E2DA3368FC823DC68C01CF1FA87190", + "PublicKey": null, + "Amount": 277 + } + ] + }, + { + "Address": "C92303227C9F0EC569B27B02DB328CFA0A7DF7E0", + "PublicKey": { + "CurveType": "ed25519", + "PublicKey": "E3C56A2C047C9C82036778620E6F9089E5FB38A5D36CE47D9545CBA930C79522" + }, + "Amount": 285, + "Name": "Baz", + "UnbondTo": [ + { + "Address": "C92303227C9F0EC569B27B02DB328CFA0A7DF7E0", + "PublicKey": null, + "Amount": 285 + } + ] + }, + { + "Address": "900EBED8C6B27F7B606B6CAD34DB03C2C5C0E541", + "PublicKey": { + "CurveType": "ed25519", + "PublicKey": "78133DE07C66C616263FD2D6A54BD3FC0D8CBF3A87BB2E0C410A0C8DEB6189CE" + }, + "Amount": 292, + "Name": "Foo", + "UnbondTo": [ + { + "Address": "900EBED8C6B27F7B606B6CAD34DB03C2C5C0E541", + "PublicKey": null, + "Amount": 292 + } + ] + } + ] +}`