|
|
@@ -1564,117 +1564,6 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Benchmarks large blocks with value transfers to non-existing accounts
|
|
|
-func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
|
|
- var (
|
|
|
- signer = types.HomesteadSigner{}
|
|
|
- testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
|
- testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
|
|
- bankFunds = big.NewInt(100000000000000000)
|
|
|
- gspec = Genesis{
|
|
|
- Config: params.TestChainConfig,
|
|
|
- Alloc: GenesisAlloc{
|
|
|
- testBankAddress: {Balance: bankFunds},
|
|
|
- common.HexToAddress("0xc0de"): {
|
|
|
- Code: []byte{0x60, 0x01, 0x50},
|
|
|
- Balance: big.NewInt(0),
|
|
|
- }, // push 1, pop
|
|
|
- },
|
|
|
- GasLimit: 100e6, // 100 M
|
|
|
- }
|
|
|
- )
|
|
|
- // Generate the original common chain segment and the two competing forks
|
|
|
- engine := ethash.NewFaker()
|
|
|
- db := rawdb.NewMemoryDatabase()
|
|
|
- genesis := gspec.MustCommit(db)
|
|
|
-
|
|
|
- blockGenerator := func(i int, block *BlockGen) {
|
|
|
- block.SetCoinbase(common.Address{1})
|
|
|
- for txi := 0; txi < numTxs; txi++ {
|
|
|
- uniq := uint64(i*numTxs + txi)
|
|
|
- recipient := recipientFn(uniq)
|
|
|
- //recipient := common.BigToAddress(big.NewInt(0).SetUint64(1337 + uniq))
|
|
|
- tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey)
|
|
|
- if err != nil {
|
|
|
- b.Error(err)
|
|
|
- }
|
|
|
- block.AddTx(tx)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator)
|
|
|
- b.StopTimer()
|
|
|
- b.ResetTimer()
|
|
|
- for i := 0; i < b.N; i++ {
|
|
|
- // Import the shared chain and the original canonical one
|
|
|
- diskdb := rawdb.NewMemoryDatabase()
|
|
|
- gspec.MustCommit(diskdb)
|
|
|
-
|
|
|
- chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
|
|
- if err != nil {
|
|
|
- b.Fatalf("failed to create tester chain: %v", err)
|
|
|
- }
|
|
|
- b.StartTimer()
|
|
|
- if _, err := chain.InsertChain(shared); err != nil {
|
|
|
- b.Fatalf("failed to insert shared chain: %v", err)
|
|
|
- }
|
|
|
- b.StopTimer()
|
|
|
- if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks {
|
|
|
- b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got)
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) {
|
|
|
- var (
|
|
|
- numTxs = 1000
|
|
|
- numBlocks = 1
|
|
|
- )
|
|
|
-
|
|
|
- recipientFn := func(nonce uint64) common.Address {
|
|
|
- return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce))
|
|
|
- }
|
|
|
- dataFn := func(nonce uint64) []byte {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
-}
|
|
|
-func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) {
|
|
|
- var (
|
|
|
- numTxs = 1000
|
|
|
- numBlocks = 1
|
|
|
- )
|
|
|
- b.StopTimer()
|
|
|
- b.ResetTimer()
|
|
|
-
|
|
|
- recipientFn := func(nonce uint64) common.Address {
|
|
|
- return common.BigToAddress(big.NewInt(0).SetUint64(1337))
|
|
|
- }
|
|
|
- dataFn := func(nonce uint64) []byte {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
-}
|
|
|
-func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
|
|
|
- var (
|
|
|
- numTxs = 1000
|
|
|
- numBlocks = 1
|
|
|
- )
|
|
|
- b.StopTimer()
|
|
|
- b.ResetTimer()
|
|
|
-
|
|
|
- recipientFn := func(nonce uint64) common.Address {
|
|
|
- return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de))
|
|
|
- }
|
|
|
- dataFn := func(nonce uint64) []byte {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
-}
|
|
|
-
|
|
|
// Tests that importing a very large side fork, which is larger than the canon chain,
|
|
|
// but where the difficulty per block is kept low: this means that it will not
|
|
|
// overtake the 'canon' chain until after it's passed canon by about 200 blocks.
|
|
|
@@ -1812,6 +1701,138 @@ func TestPrunedImportSide(t *testing.T) {
|
|
|
testSideImport(t, 1, -10)
|
|
|
}
|
|
|
|
|
|
+func TestInsertKnownHeaders(t *testing.T) { testInsertKnownChainData(t, "headers") }
|
|
|
+func TestInsertKnownReceiptChain(t *testing.T) { testInsertKnownChainData(t, "receipts") }
|
|
|
+func TestInsertKnownBlocks(t *testing.T) { testInsertKnownChainData(t, "blocks") }
|
|
|
+
|
|
|
+func testInsertKnownChainData(t *testing.T, typ string) {
|
|
|
+ engine := ethash.NewFaker()
|
|
|
+
|
|
|
+ db := rawdb.NewMemoryDatabase()
|
|
|
+ genesis := new(Genesis).MustCommit(db)
|
|
|
+
|
|
|
+ blocks, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
|
|
+ // A longer chain but total difficulty is lower.
|
|
|
+ blocks2, receipts2 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
|
|
+ // A shorter chain but total difficulty is higher.
|
|
|
+ blocks3, receipts3 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 64, func(i int, b *BlockGen) {
|
|
|
+ b.SetCoinbase(common.Address{1})
|
|
|
+ b.OffsetTime(-9) // A higher difficulty
|
|
|
+ })
|
|
|
+
|
|
|
+ // Import the shared chain and the original canonical one
|
|
|
+ chaindb := rawdb.NewMemoryDatabase()
|
|
|
+ new(Genesis).MustCommit(chaindb)
|
|
|
+
|
|
|
+ chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to create tester chain: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ inserter func(blocks []*types.Block, receipts []types.Receipts) error
|
|
|
+ asserter func(t *testing.T, block *types.Block)
|
|
|
+ )
|
|
|
+ headers, headers2 := make([]*types.Header, 0, len(blocks)), make([]*types.Header, 0, len(blocks2))
|
|
|
+ for _, block := range blocks {
|
|
|
+ headers = append(headers, block.Header())
|
|
|
+ }
|
|
|
+ for _, block := range blocks2 {
|
|
|
+ headers2 = append(headers2, block.Header())
|
|
|
+ }
|
|
|
+ if typ == "headers" {
|
|
|
+ inserter = func(blocks []*types.Block, receipts []types.Receipts) error {
|
|
|
+ headers := make([]*types.Header, 0, len(blocks))
|
|
|
+ for _, block := range blocks {
|
|
|
+ headers = append(headers, block.Header())
|
|
|
+ }
|
|
|
+ _, err := chain.InsertHeaderChain(headers, 1)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ asserter = func(t *testing.T, block *types.Block) {
|
|
|
+ if chain.CurrentHeader().Hash() != block.Hash() {
|
|
|
+ t.Fatalf("current head header mismatch, have %v, want %v", chain.CurrentHeader().Hash().Hex(), block.Hash().Hex())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if typ == "receipts" {
|
|
|
+ inserter = func(blocks []*types.Block, receipts []types.Receipts) error {
|
|
|
+ headers := make([]*types.Header, 0, len(blocks))
|
|
|
+ for _, block := range blocks {
|
|
|
+ headers = append(headers, block.Header())
|
|
|
+ }
|
|
|
+ _, err := chain.InsertHeaderChain(headers, 1)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ _, err = chain.InsertReceiptChain(blocks, receipts)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ asserter = func(t *testing.T, block *types.Block) {
|
|
|
+ if chain.CurrentFastBlock().Hash() != block.Hash() {
|
|
|
+ t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ inserter = func(blocks []*types.Block, receipts []types.Receipts) error {
|
|
|
+ _, err := chain.InsertChain(blocks)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ asserter = func(t *testing.T, block *types.Block) {
|
|
|
+ if chain.CurrentBlock().Hash() != block.Hash() {
|
|
|
+ t.Fatalf("current head block mismatch, have %v, want %v", chain.CurrentBlock().Hash().Hex(), block.Hash().Hex())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := inserter(blocks, receipts); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Reimport the chain data again. All the imported
|
|
|
+ // chain data are regarded "known" data.
|
|
|
+ if err := inserter(blocks, receipts); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+ asserter(t, blocks[len(blocks)-1])
|
|
|
+
|
|
|
+ // Import a long canonical chain with some known data as prefix.
|
|
|
+ var rollback []common.Hash
|
|
|
+ for i := len(blocks) / 2; i < len(blocks); i++ {
|
|
|
+ rollback = append(rollback, blocks[i].Hash())
|
|
|
+ }
|
|
|
+ chain.Rollback(rollback)
|
|
|
+ if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+ asserter(t, blocks2[len(blocks2)-1])
|
|
|
+
|
|
|
+ // Import a heavier shorter but higher total difficulty chain with some known data as prefix.
|
|
|
+ if err := inserter(append(blocks, blocks3...), append(receipts, receipts3...)); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+ asserter(t, blocks3[len(blocks3)-1])
|
|
|
+
|
|
|
+ // Import a longer but lower total difficulty chain with some known data as prefix.
|
|
|
+ if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+ // The head shouldn't change.
|
|
|
+ asserter(t, blocks3[len(blocks3)-1])
|
|
|
+
|
|
|
+ if typ != "headers" {
|
|
|
+ // Rollback the heavier chain and re-insert the longer chain again
|
|
|
+ for i := 0; i < len(blocks3); i++ {
|
|
|
+ rollback = append(rollback, blocks3[i].Hash())
|
|
|
+ }
|
|
|
+ chain.Rollback(rollback)
|
|
|
+
|
|
|
+ if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
|
|
+ t.Fatalf("failed to insert chain data: %v", err)
|
|
|
+ }
|
|
|
+ asserter(t, blocks2[len(blocks2)-1])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// getLongAndShortChains returns two chains,
|
|
|
// A is longer, B is heavier
|
|
|
func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, error) {
|
|
|
@@ -1931,3 +1952,116 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) {
|
|
|
t.Errorf("expected header to be gone: %v", headerByNum.Number.Uint64())
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Benchmarks large blocks with value transfers to non-existing accounts
|
|
|
+func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
|
|
+ var (
|
|
|
+ signer = types.HomesteadSigner{}
|
|
|
+ testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
|
+ testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
|
|
+ bankFunds = big.NewInt(100000000000000000)
|
|
|
+ gspec = Genesis{
|
|
|
+ Config: params.TestChainConfig,
|
|
|
+ Alloc: GenesisAlloc{
|
|
|
+ testBankAddress: {Balance: bankFunds},
|
|
|
+ common.HexToAddress("0xc0de"): {
|
|
|
+ Code: []byte{0x60, 0x01, 0x50},
|
|
|
+ Balance: big.NewInt(0),
|
|
|
+ }, // push 1, pop
|
|
|
+ },
|
|
|
+ GasLimit: 100e6, // 100 M
|
|
|
+ }
|
|
|
+ )
|
|
|
+ // Generate the original common chain segment and the two competing forks
|
|
|
+ engine := ethash.NewFaker()
|
|
|
+ db := rawdb.NewMemoryDatabase()
|
|
|
+ genesis := gspec.MustCommit(db)
|
|
|
+
|
|
|
+ blockGenerator := func(i int, block *BlockGen) {
|
|
|
+ block.SetCoinbase(common.Address{1})
|
|
|
+ for txi := 0; txi < numTxs; txi++ {
|
|
|
+ uniq := uint64(i*numTxs + txi)
|
|
|
+ recipient := recipientFn(uniq)
|
|
|
+ tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey)
|
|
|
+ if err != nil {
|
|
|
+ b.Error(err)
|
|
|
+ }
|
|
|
+ block.AddTx(tx)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator)
|
|
|
+ b.StopTimer()
|
|
|
+ b.ResetTimer()
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ // Import the shared chain and the original canonical one
|
|
|
+ diskdb := rawdb.NewMemoryDatabase()
|
|
|
+ gspec.MustCommit(diskdb)
|
|
|
+
|
|
|
+ chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
|
|
+ if err != nil {
|
|
|
+ b.Fatalf("failed to create tester chain: %v", err)
|
|
|
+ }
|
|
|
+ b.StartTimer()
|
|
|
+ if _, err := chain.InsertChain(shared); err != nil {
|
|
|
+ b.Fatalf("failed to insert shared chain: %v", err)
|
|
|
+ }
|
|
|
+ b.StopTimer()
|
|
|
+ if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks {
|
|
|
+ b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got)
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) {
|
|
|
+ var (
|
|
|
+ numTxs = 1000
|
|
|
+ numBlocks = 1
|
|
|
+ )
|
|
|
+
|
|
|
+ recipientFn := func(nonce uint64) common.Address {
|
|
|
+ return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce))
|
|
|
+ }
|
|
|
+ dataFn := func(nonce uint64) []byte {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) {
|
|
|
+ var (
|
|
|
+ numTxs = 1000
|
|
|
+ numBlocks = 1
|
|
|
+ )
|
|
|
+ b.StopTimer()
|
|
|
+ b.ResetTimer()
|
|
|
+
|
|
|
+ recipientFn := func(nonce uint64) common.Address {
|
|
|
+ return common.BigToAddress(big.NewInt(0).SetUint64(1337))
|
|
|
+ }
|
|
|
+ dataFn := func(nonce uint64) []byte {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
|
|
|
+ var (
|
|
|
+ numTxs = 1000
|
|
|
+ numBlocks = 1
|
|
|
+ )
|
|
|
+ b.StopTimer()
|
|
|
+ b.ResetTimer()
|
|
|
+
|
|
|
+ recipientFn := func(nonce uint64) common.Address {
|
|
|
+ return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de))
|
|
|
+ }
|
|
|
+ dataFn := func(nonce uint64) []byte {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
|
|
+}
|