@ -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 )
}