@ -17,13 +17,24 @@
package ethclient
import (
"context"
"errors"
"fmt"
"math/big"
"reflect"
"testing"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
)
// Verify that Client implements the ethereum interfaces.
@ -150,3 +161,143 @@ func TestToFilterArg(t *testing.T) {
} )
}
}
var (
testKey , _ = crypto . HexToECDSA ( "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
testAddr = crypto . PubkeyToAddress ( testKey . PublicKey )
testBalance = big . NewInt ( 2e10 )
)
func newTestBackend ( t * testing . T ) ( * node . Node , [ ] * types . Block ) {
// Generate test chain.
genesis , blocks := generateTestChain ( )
// Start Ethereum service.
var ethservice * eth . Ethereum
n , err := node . New ( & node . Config { } )
n . Register ( func ( ctx * node . ServiceContext ) ( node . Service , error ) {
config := & eth . Config { Genesis : genesis }
config . Ethash . PowMode = ethash . ModeFake
ethservice , err = eth . New ( ctx , config )
return ethservice , err
} )
// Import the test chain.
if err := n . Start ( ) ; err != nil {
t . Fatalf ( "can't start test node: %v" , err )
}
if _ , err := ethservice . BlockChain ( ) . InsertChain ( blocks [ 1 : ] ) ; err != nil {
t . Fatalf ( "can't import test blocks: %v" , err )
}
return n , blocks
}
func generateTestChain ( ) ( * core . Genesis , [ ] * types . Block ) {
db := rawdb . NewMemoryDatabase ( )
config := params . AllEthashProtocolChanges
genesis := & core . Genesis {
Config : config ,
Alloc : core . GenesisAlloc { testAddr : { Balance : testBalance } } ,
ExtraData : [ ] byte ( "test genesis" ) ,
Timestamp : 9000 ,
}
generate := func ( i int , g * core . BlockGen ) {
g . OffsetTime ( 5 )
g . SetExtra ( [ ] byte ( "test" ) )
}
gblock := genesis . ToBlock ( db )
engine := ethash . NewFaker ( )
blocks , _ := core . GenerateChain ( config , gblock , engine , db , 1 , generate )
blocks = append ( [ ] * types . Block { gblock } , blocks ... )
return genesis , blocks
}
func TestHeader ( t * testing . T ) {
backend , chain := newTestBackend ( t )
client , _ := backend . Attach ( )
defer backend . Stop ( )
defer client . Close ( )
tests := map [ string ] struct {
block * big . Int
want * types . Header
wantErr error
} {
"genesis" : {
block : big . NewInt ( 0 ) ,
want : chain [ 0 ] . Header ( ) ,
} ,
"first_block" : {
block : big . NewInt ( 1 ) ,
want : chain [ 1 ] . Header ( ) ,
} ,
"future_block" : {
block : big . NewInt ( 1000000000 ) ,
want : nil ,
} ,
}
for name , tt := range tests {
t . Run ( name , func ( t * testing . T ) {
ec := NewClient ( client )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 100 * time . Millisecond )
defer cancel ( )
got , err := ec . HeaderByNumber ( ctx , tt . block )
if tt . wantErr != nil && ( err == nil || err . Error ( ) != tt . wantErr . Error ( ) ) {
t . Fatalf ( "HeaderByNumber(%v) error = %q, want %q" , tt . block , err , tt . wantErr )
}
if got != nil && got . Number . Sign ( ) == 0 {
got . Number = big . NewInt ( 0 ) // hack to make DeepEqual work
}
if ! reflect . DeepEqual ( got , tt . want ) {
t . Fatalf ( "HeaderByNumber(%v)\n = %v\nwant %v" , tt . block , got , tt . want )
}
} )
}
}
func TestBalanceAt ( t * testing . T ) {
backend , _ := newTestBackend ( t )
client , _ := backend . Attach ( )
defer backend . Stop ( )
defer client . Close ( )
tests := map [ string ] struct {
account common . Address
block * big . Int
want * big . Int
wantErr error
} {
"valid_account" : {
account : testAddr ,
block : big . NewInt ( 1 ) ,
want : testBalance ,
} ,
"non_existent_account" : {
account : common . Address { 1 } ,
block : big . NewInt ( 1 ) ,
want : big . NewInt ( 0 ) ,
} ,
"future_block" : {
account : testAddr ,
block : big . NewInt ( 1000000000 ) ,
want : big . NewInt ( 0 ) ,
wantErr : errors . New ( "header not found" ) ,
} ,
}
for name , tt := range tests {
t . Run ( name , func ( t * testing . T ) {
ec := NewClient ( client )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 100 * time . Millisecond )
defer cancel ( )
got , err := ec . BalanceAt ( ctx , tt . account , tt . block )
if tt . wantErr != nil && ( err == nil || err . Error ( ) != tt . wantErr . Error ( ) ) {
t . Fatalf ( "BalanceAt(%x, %v) error = %q, want %q" , tt . account , tt . block , err , tt . wantErr )
}
if got . Cmp ( tt . want ) != 0 {
t . Fatalf ( "BalanceAt(%x, %v) = %v, want %v" , tt . account , tt . block , got , tt . want )
}
} )
}
}