Skip to content
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

[R4R]fix state inconsistent when doing diffsync #628

Merged
merged 3 commits into from
Dec 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/release.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/mainnet.zip"
TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/testnet.zip"
MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/mainnet.zip"
TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/testnet.zip"
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## v1.1.7

BUGFIX
* [\#628](https://github.com/binance-chain/bsc/pull/628) fix state inconsistent when doing diffsync

## v1.1.6
BUGFIX
* [\#582](https://github.com/binance-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9
Expand Down
115 changes: 100 additions & 15 deletions core/blockchain_diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package core

import (
"bytes"
"encoding/hex"
"math/big"
"testing"
"time"
Expand All @@ -42,17 +44,51 @@ import (

var (
// testKey is a private key to use for funding a tester account.
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
contractCode, _ = hex.DecodeString("608060405260016000806101000a81548160ff02191690831515021790555034801561002a57600080fd5b506101688061003a6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806389a2d8011461003b578063b0483f4814610059575b600080fd5b610043610075565b60405161005091906100f4565b60405180910390f35b610073600480360381019061006e91906100bc565b61008b565b005b60008060009054906101000a900460ff16905090565b806000806101000a81548160ff02191690831515021790555050565b6000813590506100b68161011b565b92915050565b6000602082840312156100ce57600080fd5b60006100dc848285016100a7565b91505092915050565b6100ee8161010f565b82525050565b600060208201905061010960008301846100e5565b92915050565b60008115159050919050565b6101248161010f565b811461012f57600080fd5b5056fea264697066735822122092f788b569bfc3786e90601b5dbec01cfc3d76094164fd66ca7d599c4239fc5164736f6c63430008000033")
contractAddr = common.HexToAddress("0xe74a3c7427cda785e0000d42a705b1f3fd371e09")
contractSlot = common.HexToHash("0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
contractData1, _ = hex.DecodeString("b0483f480000000000000000000000000000000000000000000000000000000000000000")
contractData2, _ = hex.DecodeString("b0483f480000000000000000000000000000000000000000000000000000000000000001")
commonGas = 192138
// testAddr is the Ethereum address of the tester account.
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)

checkBlocks = map[int]checkBlockParam{
12: {
txs: []checkTransactionParam{
{
to: &contractAddr,
slot: contractSlot,
value: []byte{01},
},
}},

13: {
txs: []checkTransactionParam{
{
to: &contractAddr,
slot: contractSlot,
value: []byte{},
},
}},
14: {
txs: []checkTransactionParam{
{
to: &contractAddr,
slot: contractSlot,
value: []byte{01},
},
}},
}
// testBlocks is the test parameters array for specific blocks.
testBlocks = []testBlockParam{
{
// This txs params also used to default block.
blockNr: 11,
txs: []testTransactionParam{
{
to: common.Address{0x01},
to: &common.Address{0x01},
value: big.NewInt(1),
gasPrice: big.NewInt(1),
data: nil,
Expand All @@ -63,51 +99,74 @@ var (
blockNr: 12,
txs: []testTransactionParam{
{
to: common.Address{0x01},
to: &common.Address{0x01},
value: big.NewInt(1),
gasPrice: big.NewInt(1),
data: nil,
},
{
to: common.Address{0x02},
to: &common.Address{0x02},
value: big.NewInt(2),
gasPrice: big.NewInt(2),
data: nil,
},
{
to: nil,
value: big.NewInt(0),
gasPrice: big.NewInt(2),
data: contractCode,
},
},
},
{
blockNr: 13,
txs: []testTransactionParam{
{
to: common.Address{0x01},
to: &common.Address{0x01},
value: big.NewInt(1),
gasPrice: big.NewInt(1),
data: nil,
},
{
to: common.Address{0x02},
to: &common.Address{0x02},
value: big.NewInt(2),
gasPrice: big.NewInt(2),
data: nil,
},
{
to: common.Address{0x03},
to: &common.Address{0x03},
value: big.NewInt(3),
gasPrice: big.NewInt(3),
data: nil,
},
{
to: &contractAddr,
value: big.NewInt(0),
gasPrice: big.NewInt(3),
data: contractData1,
},
},
},
{
blockNr: 14,
txs: []testTransactionParam{
{
to: &contractAddr,
value: big.NewInt(0),
gasPrice: big.NewInt(3),
data: contractData2,
},
},
},
{
blockNr: 15,
txs: []testTransactionParam{},
},
}
)

type testTransactionParam struct {
to common.Address
to *common.Address
value *big.Int
gasPrice *big.Int
data []byte
Expand All @@ -118,6 +177,16 @@ type testBlockParam struct {
txs []testTransactionParam
}

type checkTransactionParam struct {
to *common.Address
slot common.Hash
value []byte
}

type checkBlockParam struct {
txs []checkTransactionParam
}

// testBackend is a mock implementation of the live Ethereum message handler. Its
// purpose is to allow testing the request/reply workflows and wire serialization
// in the `eth` protocol without actually doing any data processing.
Expand Down Expand Up @@ -153,8 +222,15 @@ func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend {
// Specific block setting, the index in this generator has 1 diff from specified blockNr.
if i+1 == testBlock.blockNr {
for _, testTransaction := range testBlock.txs {
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to,
testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey)
var transaction *types.Transaction
if testTransaction.to == nil {
transaction = types.NewContractCreation(block.TxNonce(testAddr),
testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data)
} else {
transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to,
testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data)
}
tx, err := types.SignTx(transaction, signer, testKey)
if err != nil {
panic(err)
}
Expand All @@ -168,8 +244,8 @@ func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend {
// We want to simulate an empty middle block, having the same state as the
// first one. The last is needs a state change again to force a reorg.
for _, testTransaction := range testBlocks[0].txs {
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to,
testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey)
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to,
testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -241,6 +317,14 @@ func TestProcessDiffLayer(t *testing.T) {
lightBackend.Chain().HandleDiffLayer(diff, "testpid", true)
}
_, err := lightBackend.chain.insertChain([]*types.Block{block}, true)
if checks, exist := checkBlocks[i]; exist {
for _, check := range checks.txs {
s, _ := lightBackend.Chain().Snapshots().Snapshot(block.Root()).Storage(crypto.Keccak256Hash((*check.to)[:]), check.slot)
if !bytes.Equal(s, check.value) {
t.Fatalf("Expected value %x, get %x", check.value, s)
}
}
}
if err != nil {
t.Errorf("failed to insert block %v", err)
}
Expand Down Expand Up @@ -385,13 +469,14 @@ func TestGetDiffAccounts(t *testing.T) {
t.Errorf("the diff accounts does't include addr: %v", testAddr)
}
}

for _, transaction := range testBlock.txs {
if transaction.to == nil || len(transaction.data) > 0 {
continue
}
for idx, account := range accounts {
if transaction.to == account {
if *transaction.to == account {
break
}

if idx == len(accounts)-1 {
t.Errorf("the diff accounts does't include addr: %v", transaction.to)
}
Expand Down
2 changes: 1 addition & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty

//update storage
latestRoot := common.BytesToHash(latestAccount.Root)
if latestRoot != previousAccount.Root && latestRoot != types.EmptyRootHash {
if latestRoot != previousAccount.Root {
accountTrie, err := statedb.Database().OpenStorageTrie(addrHash, previousAccount.Root)
if err != nil {
errChan <- err
Expand Down
2 changes: 1 addition & 1 deletion params/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 1 // Minor version component of the current release
VersionPatch = 6 // Patch version component of the current release
VersionPatch = 7 // Patch version component of the current release
VersionMeta = "" // Version metadata to append to the version string
)

Expand Down