Skip to content

Commit

Permalink
testcases for getting root by diff hash
Browse files Browse the repository at this point in the history
  • Loading branch information
keefel committed Jan 26, 2022
1 parent 885aeb9 commit 66dd9ea
Showing 1 changed file with 160 additions and 0 deletions.
160 changes: 160 additions & 0 deletions core/blockchain_diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,163 @@ func TestGetDiffAccounts(t *testing.T) {
}
}
}

// newTwoForkedBlockchains returns two blockchains, these two chains are generated by different
// generators, they have some same parent blocks, the number of same blocks are determined by
// testBlocks, once chain1 inserted a non-default block, chain1 and chain2 get forked.
func newTwoForkedBlockchains(len1, len2 int) (chain1 *BlockChain, chain2 *BlockChain) {
signer := types.HomesteadSigner{}
// Create a database pre-initialize with a genesis block
db1 := rawdb.NewMemoryDatabase()
db1.SetDiffStore(memorydb.New())
(&Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}},
}).MustCommit(db1)

chain1, _ = NewBlockChain(db1, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, EnablePersistDiff(860000))
generator1 := func(i int, block *BlockGen) {
// The chain maker doesn't have access to a chain, so the difficulty will be
// lets unset (nil). Set it here to the correct value.
block.SetCoinbase(testAddr)

for idx, testBlock := range testBlocks {
// Specific block setting, the index in this generator has 1 diff from specified blockNr.
if i+1 == testBlock.blockNr {
for _, testTransaction := range testBlock.txs {
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)
}
block.AddTxWithChain(chain1, tx)
}
break
}

// Default block setting.
if idx == len(testBlocks)-1 {
// 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, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey)
if err != nil {
panic(err)
}
block.AddTxWithChain(chain1, tx)
}
}
}

}
bs1, _ := GenerateChain(params.TestChainConfig, chain1.Genesis(), ethash.NewFaker(), db1, len1, generator1)
if _, err := chain1.InsertChain(bs1); err != nil {
panic(err)
}

// Create a database pre-initialize with a genesis block
db2 := rawdb.NewMemoryDatabase()
db2.SetDiffStore(memorydb.New())
(&Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}},
}).MustCommit(db2)
chain2, _ = NewBlockChain(db2, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, EnablePersistDiff(860000))
generator2 := func(i int, block *BlockGen) {
// The chain maker doesn't have access to a chain, so the difficulty will be
// lets unset (nil). Set it here to the correct value.
block.SetCoinbase(testAddr)
// 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, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey)
if err != nil {
panic(err)
}
block.AddTxWithChain(chain1, tx)
}
}
bs2, _ := GenerateChain(params.TestChainConfig, chain2.Genesis(), ethash.NewFaker(), db2, len2, generator2)
if _, err := chain2.InsertChain(bs2); err != nil {
panic(err)
}

return chain1, chain2
}

func testGetRootByDiffHash(t *testing.T, chain1, chain2 *BlockChain, blockNumber uint64, status types.VerifyStatus) {
block2 := chain2.GetBlockByNumber(blockNumber)
if block2 == nil {
t.Fatalf("failed to find block, number: %v", blockNumber)
}
expect := types.VerifyResult{
Status: status,
BlockNumber: blockNumber,
BlockHash: block2.Hash(),
}
if status.Code&0xff00 == types.StatusVerified.Code {
expect.Root = block2.Root()
}

diffLayer2 := chain2.GetTrustedDiffLayer(block2.Hash())
if diffLayer2 == nil {
t.Fatal("failed to find diff layer")
}
diffHash2 := types.EmptyRootHash
if status != types.StatusDiffHashMismatch {
var err error
diffHash2, err = GetTrustedDiffHash(diffLayer2)
if err != nil {
t.Fatalf("failed to compute diff hash: %v", err)
}
}

if status == types.StatusUntrustedVerified {
block1 := chain1.GetBlockByNumber(blockNumber)
if block1 == nil {
t.Fatalf("failed to find block, number: %v", blockNumber)
}
chain1.diffLayerCache.Remove(block1.Hash())
}

result, _ := chain1.GetRootByDiffHash(blockNumber, block2.Hash(), diffHash2)
if result.Status != expect.Status {
t.Fatalf("failed to verify block, number: %v, expect status: %v, real status: %v", blockNumber, expect.Status, result.Status)
}
if result.Root != expect.Root {
t.Fatalf("failed to verify block, number: %v, expect root: %v, real root: %v", blockNumber, expect.Root, result.Root)
}
}

func TestGetRootByDiffHash(t *testing.T) {
len1 := 23 // length of blockchain1
len2 := 35 // length of blockchain2
plen := 11 // length of same parent blocks, which determined by testBlocks.

chain1, chain2 := newTwoForkedBlockchains(len1, len2)
defer chain1.Stop()
defer chain2.Stop()

hash1 := chain1.GetBlockByNumber(uint64(plen)).Hash()
hash2 := chain2.GetBlockByNumber(uint64(plen)).Hash()
if hash1 != hash2 {
t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", plen, hash2, hash1)
}

testGetRootByDiffHash(t, chain1, chain2, 10, types.StatusFullVerified)
testGetRootByDiffHash(t, chain1, chain2, 2, types.StatusUntrustedVerified)
testGetRootByDiffHash(t, chain1, chain2, 10, types.StatusDiffHashMismatch)
testGetRootByDiffHash(t, chain1, chain2, 12, types.StatusImpossibleFork)
testGetRootByDiffHash(t, chain1, chain2, 20, types.StatusPossibleFork)
testGetRootByDiffHash(t, chain1, chain2, 24, types.StatusBlockNewer)
testGetRootByDiffHash(t, chain1, chain2, 35, types.StatusBlockTooNew)
}

0 comments on commit 66dd9ea

Please sign in to comment.