Merge pull request #3179 from obscuren/eip-158

EIP158 & 160 Hardfork
This commit is contained in:
Felix Lange 2016-11-14 10:52:02 +01:00 committed by GitHub
commit ca73dea3b9
961 changed files with 149770 additions and 66826 deletions

View File

@ -48,15 +48,15 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
keyAddr := crypto.PubkeyToAddress(key.PublicKey) keyAddr := crypto.PubkeyToAddress(key.PublicKey)
return &TransactOpts{ return &TransactOpts{
From: keyAddr, From: keyAddr,
Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) {
if address != keyAddr { if address != keyAddr {
return nil, errors.New("not authorized to sign this account") return nil, errors.New("not authorized to sign this account")
} }
signature, err := crypto.SignEthereum(tx.SigHash().Bytes(), key) signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return tx.WithSignature(signature) return tx.WithSignature(signer, signature)
}, },
} }
} }

View File

@ -31,11 +31,12 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier) // Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
var chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
var _ bind.ContractBackend = (*SimulatedBackend)(nil) var _ bind.ContractBackend = (*SimulatedBackend)(nil)
@ -51,6 +52,8 @@ type SimulatedBackend struct {
mu sync.Mutex mu sync.Mutex
pendingBlock *types.Block // Currently pending block that will be imported on request pendingBlock *types.Block // Currently pending block that will be imported on request
pendingState *state.StateDB // Currently pending state that will be the active on on request pendingState *state.StateDB // Currently pending state that will be the active on on request
config *params.ChainConfig
} }
// NewSimulatedBackend creates a new binding backend using a simulated blockchain // NewSimulatedBackend creates a new binding backend using a simulated blockchain
@ -85,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
} }
func (b *SimulatedBackend) rollback() { func (b *SimulatedBackend) rollback() {
blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
} }
@ -234,7 +237,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
sender, err := tx.From() sender, err := types.Sender(types.HomesteadSigner{}, tx)
if err != nil { if err != nil {
panic(fmt.Errorf("invalid transaction: %v", err)) panic(fmt.Errorf("invalid transaction: %v", err))
} }
@ -243,7 +246,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
} }
blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() { for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx) block.AddTx(tx)
} }
@ -259,12 +262,11 @@ type callmsg struct {
ethereum.CallMsg ethereum.CallMsg
} }
func (m callmsg) From() (common.Address, error) { return m.CallMsg.From, nil } func (m callmsg) From() common.Address { return m.CallMsg.From }
func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil } func (m callmsg) Nonce() uint64 { return 0 }
func (m callmsg) Nonce() uint64 { return 0 } func (m callmsg) CheckNonce() bool { return false }
func (m callmsg) CheckNonce() bool { return false } func (m callmsg) To() *common.Address { return m.CallMsg.To }
func (m callmsg) To() *common.Address { return m.CallMsg.To } func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas } func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
func (m callmsg) Value() *big.Int { return m.CallMsg.Value } func (m callmsg) Data() []byte { return m.CallMsg.Data }
func (m callmsg) Data() []byte { return m.CallMsg.Data }

View File

@ -31,7 +31,7 @@ import (
// SignerFn is a signer function callback when a contract requires a method to // SignerFn is a signer function callback when a contract requires a method to
// sign the transaction before submission. // sign the transaction before submission.
type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error)
// CallOpts is the collection of options to fine tune a contract call request. // CallOpts is the collection of options to fine tune a contract call request.
type CallOpts struct { type CallOpts struct {
@ -214,7 +214,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if opts.Signer == nil { if opts.Signer == nil {
return nil, errors.New("no signer to authorize the transaction with") return nil, errors.New("no signer to authorize the transaction with")
} }
signedTx, err := opts.Signer(opts.From, rawTx) signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
// Create the transaction. // Create the transaction.
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
tx, _ = tx.SignECDSA(testKey) tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey)
// Wait for it to get mined in the background. // Wait for it to get mined in the background.
var ( var (

View File

@ -76,10 +76,11 @@ func runTestWithReader(test string, r io.Reader) error {
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests": case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests) err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests)
case "st", "state", "statetest", "statetests": case "st", "state", "statetest", "statetests":
rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true} rs := &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true, EIP150Block: params.MainNetHomesteadGasRepriceBlock}
err = tests.RunStateTestWithReader(rs, r, skipTests) err = tests.RunStateTestWithReader(rs, r, skipTests)
case "tx", "transactiontest", "transactiontests": case "tx", "transactiontest", "transactiontests":
err = tests.RunTransactionTestsWithReader(r, skipTests) rs := &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true, EIP150Block: params.MainNetHomesteadGasRepriceBlock}
err = tests.RunTransactionTestsWithReader(rs, r, skipTests)
case "vm", "vmtest", "vmtests": case "vm", "vmtest", "vmtests":
err = tests.RunVmTestWithReader(r, skipTests) err = tests.RunVmTestWithReader(r, skipTests)
case "rlp", "rlptest", "rlptests": case "rlp", "rlptest", "rlptests":

View File

@ -191,7 +191,7 @@ func run(ctx *cli.Context) error {
vmdone := time.Since(tstart) vmdone := time.Since(tstart)
if ctx.GlobalBool(DumpFlag.Name) { if ctx.GlobalBool(DumpFlag.Name) {
statedb.Commit() statedb.Commit(true)
fmt.Println(string(statedb.Dump())) fmt.Println(string(statedb.Dump()))
} }
vm.StdErrFormat(logger.StructLogs()) vm.StdErrFormat(logger.StructLogs())
@ -251,7 +251,7 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg
return env return env
} }
// ruleSet implements vm.RuleSet and will always default to the homestead rule set. // ruleSet implements vm.ChainConfig and will always default to the homestead rule set.
type ruleSet struct{} type ruleSet struct{}
func (ruleSet) IsHomestead(*big.Int) bool { return true } func (ruleSet) IsHomestead(*big.Int) bool { return true }
@ -259,22 +259,22 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
return params.GasTableHomesteadGasRepriceFork return params.GasTableHomesteadGasRepriceFork
} }
func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} } func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig }
func (self *VMEnv) Vm() vm.Vm { return self.evm } func (self *VMEnv) Vm() vm.Vm { return self.evm }
func (self *VMEnv) Db() vm.Database { return self.state } func (self *VMEnv) Db() vm.Database { return self.state }
func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() } func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() }
func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) } func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
func (self *VMEnv) Origin() common.Address { return *self.transactor } func (self *VMEnv) Origin() common.Address { return *self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
func (self *VMEnv) Coinbase() common.Address { return *self.transactor } func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
func (self *VMEnv) Time() *big.Int { return self.time } func (self *VMEnv) Time() *big.Int { return self.time }
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy }
func (self *VMEnv) Depth() int { return 0 } func (self *VMEnv) Depth() int { return 0 }
func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) GetHash(n uint64) common.Hash { func (self *VMEnv) GetHash(n uint64) common.Hash {
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 { if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
return self.block.Hash() return self.block.Hash()

View File

@ -23,7 +23,6 @@ import (
"os" "os"
"os/signal" "os/signal"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -122,7 +121,7 @@ func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) {
ethConf := &eth.Config{ ethConf := &eth.Config{
TestGenesisState: db, TestGenesisState: db,
TestGenesisBlock: test.Genesis, TestGenesisBlock: test.Genesis,
ChainConfig: &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock}, ChainConfig: &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
} }
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
return nil, err return nil, err

View File

@ -801,7 +801,7 @@ func SetupNetwork(ctx *cli.Context) {
} }
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir. // MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig { func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
db := MakeChainDatabase(ctx, stack) db := MakeChainDatabase(ctx, stack)
defer db.Close() defer db.Close()
@ -809,9 +809,9 @@ func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig {
} }
// MakeChainConfigFromDb reads the chain configuration from the given database. // MakeChainConfigFromDb reads the chain configuration from the given database.
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig { func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
// If the chain is already initialized, use any existing chain configs // If the chain is already initialized, use any existing chain configs
config := new(core.ChainConfig) config := new(params.ChainConfig)
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0) genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
if genesis != nil { if genesis != nil {
@ -825,6 +825,10 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfi
Fatalf("Could not make chain configuration: %v", err) Fatalf("Could not make chain configuration: %v", err)
} }
} }
// set chain id in case it's zero.
if config.ChainId == nil {
config.ChainId = new(big.Int)
}
// Check whether we are allowed to set default config params or not: // Check whether we are allowed to set default config params or not:
// - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`) // - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet) // - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
@ -849,21 +853,37 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfi
} }
config.DAOForkSupport = true config.DAOForkSupport = true
} }
if config.HomesteadGasRepriceBlock == nil { if config.EIP150Block == nil {
if ctx.GlobalBool(TestNetFlag.Name) { if ctx.GlobalBool(TestNetFlag.Name) {
config.HomesteadGasRepriceBlock = params.TestNetHomesteadGasRepriceBlock config.EIP150Block = params.TestNetHomesteadGasRepriceBlock
} else { } else {
config.HomesteadGasRepriceBlock = params.MainNetHomesteadGasRepriceBlock config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
} }
} }
if config.HomesteadGasRepriceHash == (common.Hash{}) { if config.EIP150Hash == (common.Hash{}) {
if ctx.GlobalBool(TestNetFlag.Name) { if ctx.GlobalBool(TestNetFlag.Name) {
config.HomesteadGasRepriceHash = params.TestNetHomesteadGasRepriceHash config.EIP150Hash = params.TestNetHomesteadGasRepriceHash
} else { } else {
config.HomesteadGasRepriceHash = params.MainNetHomesteadGasRepriceHash config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
} }
} }
if config.EIP155Block == nil {
if ctx.GlobalBool(TestNetFlag.Name) {
config.EIP150Block = params.TestNetSpuriousDragon
} else {
config.EIP155Block = params.MainNetSpuriousDragon
}
}
if config.EIP158Block == nil {
if ctx.GlobalBool(TestNetFlag.Name) {
config.EIP158Block = params.TestNetSpuriousDragon
} else {
config.EIP158Block = params.MainNetSpuriousDragon
}
}
config.DAOForkSupport = true
} }
// Force override any existing configs if explicitly requested // Force override any existing configs if explicitly requested
switch { switch {
case ctx.GlobalBool(SupportDAOFork.Name): case ctx.GlobalBool(SupportDAOFork.Name):

View File

@ -32,11 +32,12 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
) )
// registryAPIBackend is a backend for an Ethereum Registry. // registryAPIBackend is a backend for an Ethereum Registry.
type registryAPIBackend struct { type registryAPIBackend struct {
config *core.ChainConfig config *params.ChainConfig
bc *core.BlockChain bc *core.BlockChain
chainDb ethdb.Database chainDb ethdb.Database
txPool *core.TxPool txPool *core.TxPool
@ -45,12 +46,12 @@ type registryAPIBackend struct {
// PrivateRegistarAPI offers various functions to access the Ethereum registry. // PrivateRegistarAPI offers various functions to access the Ethereum registry.
type PrivateRegistarAPI struct { type PrivateRegistarAPI struct {
config *core.ChainConfig config *params.ChainConfig
be *registryAPIBackend be *registryAPIBackend
} }
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance. // NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI { func NewPrivateRegistarAPI(config *params.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
return &PrivateRegistarAPI{ return &PrivateRegistarAPI{
config: config, config: config,
be: &registryAPIBackend{ be: &registryAPIBackend{
@ -173,25 +174,20 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
msg := callmsg{ var to *common.Address
from: from,
gas: common.Big(gasStr),
gasPrice: common.Big(gasPriceStr),
value: common.Big(valueStr),
data: common.FromHex(dataStr),
}
if len(toStr) > 0 { if len(toStr) > 0 {
addr := common.HexToAddress(toStr) addr := common.HexToAddress(toStr)
msg.to = &addr to = &addr
} }
gas := common.Big(gasStr)
if msg.gas.Cmp(big.NewInt(0)) == 0 { if gas.BitLen() == 0 {
msg.gas = big.NewInt(50000000) gas = big.NewInt(50000000)
} }
gasPrice := common.Big(gasPriceStr)
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 { if gasPrice.BitLen() == 0 {
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
} }
msg := types.NewMessage(from.Address(), to, 0, common.Big(valueStr), gas, gasPrice, common.FromHex(dataStr))
header := be.bc.CurrentBlock().Header() header := be.bc.CurrentBlock().Header()
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{}) vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
@ -257,11 +253,12 @@ func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasSt
tx = types.NewTransaction(nonce, to, value, gas, price, data) tx = types.NewTransaction(nonce, to, value, gas, price, data)
} }
signature, err := be.am.SignEthereum(from, tx.SigHash().Bytes()) sigHash := (types.HomesteadSigner{}).Hash(tx)
signature, err := be.am.SignEthereum(from, sigHash.Bytes())
if err != nil { if err != nil {
return "", err return "", err
} }
signedTx, err := tx.WithSignature(signature) signedTx, err := tx.WithSignature(types.HomesteadSigner{}, signature)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -28,10 +28,10 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/jsre"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
) )
const ( const (
@ -97,7 +97,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err) t.Fatalf("failed to create node: %v", err)
} }
ethConf := &eth.Config{ ethConf := &eth.Config{
ChainConfig: &core.ChainConfig{HomesteadBlock: new(big.Int)}, ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
Etherbase: common.HexToAddress(testAddress), Etherbase: common.HexToAddress(testAddress),
PowTest: true, PowTest: true,
} }

View File

@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) data := make([]byte, nbytes)
gas := IntrinsicGas(data, false, false) gas := IntrinsicGas(data, false, false)
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey) tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey)
gen.AddTx(tx) gen.AddTx(tx)
} }
} }
@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
nil, nil,
nil, nil,
) )
tx, _ = tx.SignECDSA(ringKeys[from]) tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from])
gen.AddTx(tx) gen.AddTx(tx)
from = to from = to
} }
@ -163,12 +163,12 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Generate a chain of b.N blocks using the supplied block // Generate a chain of b.N blocks using the supplied block
// generator function. // generator function.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds}) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
chain, _ := GenerateChain(nil, genesis, db, b.N, gen) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
// Time the insertion of the new chain. // Time the insertion of the new chain.
// State and blocks are stored in the same DB. // State and blocks are stored in the same DB.
evmux := new(event.TypeMux) evmux := new(event.TypeMux)
chainman, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux) chainman, _ := NewBlockChain(db, &params.ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux)
defer chainman.Stop() defer chainman.Stop()
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()

View File

@ -41,13 +41,13 @@ var (
// //
// BlockValidator implements Validator. // BlockValidator implements Validator.
type BlockValidator struct { type BlockValidator struct {
config *ChainConfig // Chain configuration options config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain bc *BlockChain // Canonical block chain
Pow pow.PoW // Proof of work used for validating Pow pow.PoW // Proof of work used for validating
} }
// NewBlockValidator returns a new block validator which is safe for re-use // NewBlockValidator returns a new block validator which is safe for re-use
func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator { func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
validator := &BlockValidator{ validator := &BlockValidator{
config: config, config: config,
Pow: pow, Pow: pow,
@ -128,7 +128,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
} }
// Validate the state root against the received state root and throw // Validate the state root against the received state root and throw
// an error if they don't match. // an error if they don't match.
if root := statedb.IntermediateRoot(); header.Root != root { if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root) return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
} }
return nil return nil
@ -203,7 +203,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
// Validates a header. Returns an error if the header is invalid. // Validates a header. Returns an error if the header is invalid.
// //
// See YP section 4.3.4. "Block Header Validity" // See YP section 4.3.4. "Block Header Validity"
func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error { func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra)) return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
} }
@ -251,9 +251,9 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
if err := ValidateDAOHeaderExtraData(config, header); err != nil { if err := ValidateDAOHeaderExtraData(config, header); err != nil {
return err return err
} }
if config.HomesteadGasRepriceBlock != nil && config.HomesteadGasRepriceBlock.Cmp(header.Number) == 0 { if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
if config.HomesteadGasRepriceHash != (common.Hash{}) && config.HomesteadGasRepriceHash != header.Hash() { if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.HomesteadGasRepriceHash) return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash)
} }
} }
return nil return nil
@ -262,7 +262,7 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
// CalcDifficulty is the difficulty adjustment algorithm. It returns // CalcDifficulty is the difficulty adjustment algorithm. It returns
// the difficulty that a new block should have when created at time // the difficulty that a new block should have when created at time
// given the parent block's time and difficulty. // given the parent block's time and difficulty.
func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff) return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
} else { } else {

View File

@ -27,11 +27,13 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow/ezp" "github.com/ethereum/go-ethereum/pow/ezp"
) )
func testChainConfig() *ChainConfig { func testChainConfig() *params.ChainConfig {
return &ChainConfig{HomesteadBlock: big.NewInt(0)} return params.TestChainConfig
//return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
} }
func proc() (Validator, *BlockChain) { func proc() (Validator, *BlockChain) {
@ -51,15 +53,15 @@ func TestNumber(t *testing.T) {
_, chain := proc() _, chain := proc()
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
header := makeHeader(chain.Genesis(), statedb)
header.Number = big.NewInt(3)
cfg := testChainConfig() cfg := testChainConfig()
header := makeHeader(cfg, chain.Genesis(), statedb)
header.Number = big.NewInt(3)
err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
if err != BlockNumberErr { if err != BlockNumberErr {
t.Errorf("expected block number error, got %q", err) t.Errorf("expected block number error, got %q", err)
} }
header = makeHeader(chain.Genesis(), statedb) header = makeHeader(cfg, chain.Genesis(), statedb)
err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
if err == BlockNumberErr { if err == BlockNumberErr {
t.Errorf("didn't expect block number error") t.Errorf("didn't expect block number error")

View File

@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -78,7 +79,7 @@ const (
// included in the canonical one where as GetBlockByNumber always represents the // included in the canonical one where as GetBlockByNumber always represents the
// canonical chain. // canonical chain.
type BlockChain struct { type BlockChain struct {
config *ChainConfig // chain & network configuration config *params.ChainConfig // chain & network configuration
hc *HeaderChain hc *HeaderChain
chainDb ethdb.Database chainDb ethdb.Database
@ -113,7 +114,7 @@ type BlockChain struct {
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
// available in the database. It initialiser the default Ethereum Validator and // available in the database. It initialiser the default Ethereum Validator and
// Processor. // Processor.
func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) { func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
bodyCache, _ := lru.New(bodyCacheLimit) bodyCache, _ := lru.New(bodyCacheLimit)
bodyRLPCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit)
blockCache, _ := lru.New(blockCacheLimit) blockCache, _ := lru.New(blockCacheLimit)
@ -633,17 +634,19 @@ func (self *BlockChain) Rollback(chain []common.Hash) {
} }
// SetReceiptsData computes all the non-consensus fields of the receipts // SetReceiptsData computes all the non-consensus fields of the receipts
func SetReceiptsData(block *types.Block, receipts types.Receipts) { func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {
signer := types.MakeSigner(config, block.Number())
transactions, logIndex := block.Transactions(), uint(0) transactions, logIndex := block.Transactions(), uint(0)
for j := 0; j < len(receipts); j++ { for j := 0; j < len(receipts); j++ {
// The transaction hash can be retrieved from the transaction itself // The transaction hash can be retrieved from the transaction itself
receipts[j].TxHash = transactions[j].Hash() receipts[j].TxHash = transactions[j].Hash()
tx, _ := transactions[j].AsMessage(signer)
// The contract address can be derived from the transaction itself // The contract address can be derived from the transaction itself
if MessageCreatesContract(transactions[j]) { if MessageCreatesContract(tx) {
from, _ := transactions[j].From() receipts[j].ContractAddress = crypto.CreateAddress(tx.From(), tx.Nonce())
receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce())
} }
// The used gas can be calculated based on previous receipts // The used gas can be calculated based on previous receipts
if j == 0 { if j == 0 {
@ -665,6 +668,7 @@ func SetReceiptsData(block *types.Block, receipts types.Receipts) {
// InsertReceiptChain attempts to complete an already existing header chain with // InsertReceiptChain attempts to complete an already existing header chain with
// transaction and receipt data. // transaction and receipt data.
// XXX should this be moved to the test?
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
self.wg.Add(1) self.wg.Add(1)
defer self.wg.Done() defer self.wg.Done()
@ -704,7 +708,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
continue continue
} }
// Compute all the non-consensus fields of the receipts // Compute all the non-consensus fields of the receipts
SetReceiptsData(block, receipts) SetReceiptsData(self.config, block, receipts)
// Write all the data out into the database // Write all the data out into the database
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil { if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
errs[index] = fmt.Errorf("failed to write block body: %v", err) errs[index] = fmt.Errorf("failed to write block body: %v", err)
@ -924,7 +928,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return i, err return i, err
} }
// Process block using the parent state as reference point. // Process block using the parent state as reference point.
receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, self.config.VmConfig) receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, vm.Config{})
if err != nil { if err != nil {
reportBlock(block, err) reportBlock(block, err)
return i, err return i, err
@ -936,7 +940,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return i, err return i, err
} }
// Write state changes to database // Write state changes to database
_, err = self.stateCache.Commit() _, err = self.stateCache.Commit(self.config.IsEIP158(block.Number()))
if err != nil { if err != nil {
return i, err return i, err
} }
@ -1309,4 +1313,4 @@ func (self *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
} }
// Config retrieves the blockchain's chain configuration. // Config retrieves the blockchain's chain configuration.
func (self *BlockChain) Config() *ChainConfig { return self.config } func (self *BlockChain) Config() *params.ChainConfig { return self.config }

View File

@ -154,7 +154,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
blockchain.mu.Lock() blockchain.mu.Lock()
WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))
WriteBlock(blockchain.chainDb, block) WriteBlock(blockchain.chainDb, block)
statedb.Commit() statedb.Commit(false)
blockchain.mu.Unlock() blockchain.mu.Unlock()
} }
return nil return nil
@ -711,14 +711,15 @@ func TestFastVsFullChains(t *testing.T) {
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds) genesis = GenesisBlockForTesting(gendb, address, funds)
signer = types.NewEIP155Signer(big.NewInt(1))
) )
blocks, receipts := GenerateChain(nil, genesis, gendb, 1024, func(i int, block *BlockGen) { blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00}) block.SetCoinbase(common.Address{0x00})
// If the block number is multiple of 3, send a few bonus transactions to the miner // If the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 { if i%3 == 2 {
for j := 0; j < i%4+1; j++ { for j := 0; j < i%4+1; j++ {
tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key) tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -795,7 +796,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
genesis = GenesisBlockForTesting(gendb, address, funds) genesis = GenesisBlockForTesting(gendb, address, funds)
) )
height := uint64(1024) height := uint64(1024)
blocks, receipts := GenerateChain(nil, genesis, gendb, int(height), nil) blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
// Configure a subchain to roll back // Configure a subchain to roll back
remove := []common.Hash{} remove := []common.Hash{}
@ -872,6 +873,7 @@ func TestChainTxReorgs(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
signer = types.NewEIP155Signer(big.NewInt(1))
) )
genesis := WriteGenesisBlockForTesting(db, genesis := WriteGenesisBlockForTesting(db,
GenesisAccount{addr1, big.NewInt(1000000)}, GenesisAccount{addr1, big.NewInt(1000000)},
@ -881,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains: // Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain // - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain // - swapped: transaction included at the same block number in the forked chain
postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
// Create two transactions that will be dropped by the forked chain: // Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block // - pastDrop: transaction dropped retroactively from a past block
@ -895,16 +897,16 @@ func TestChainTxReorgs(t *testing.T) {
// - futureAdd: transaction added after the reorg has already finished // - futureAdd: transaction added after the reorg has already finished
var pastAdd, freshAdd, futureAdd *types.Transaction var pastAdd, freshAdd, futureAdd *types.Transaction
chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
case 2: case 2:
freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
gen.AddTx(swapped) // This transaction will be swapped out at the exact height gen.AddTx(swapped) // This transaction will be swapped out at the exact height
@ -920,21 +922,21 @@ func TestChainTxReorgs(t *testing.T) {
} }
// overwrite the old chain // overwrite the old chain
chain, _ = GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
case 2: case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
case 3: case 3:
futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
gen.AddTx(futureAdd) // This transaction will be added after a full reorg gen.AddTx(futureAdd) // This transaction will be added after a full reorg
} }
}) })
@ -980,7 +982,8 @@ func TestLogReorgs(t *testing.T) {
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
// this code generates a log // this code generates a log
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
signer = types.NewEIP155Signer(big.NewInt(1))
) )
genesis := WriteGenesisBlockForTesting(db, genesis := WriteGenesisBlockForTesting(db,
GenesisAccount{addr1, big.NewInt(10000000000000)}, GenesisAccount{addr1, big.NewInt(10000000000000)},
@ -990,9 +993,9 @@ func TestLogReorgs(t *testing.T) {
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
subs := evmux.Subscribe(RemovedLogsEvent{}) subs := evmux.Subscribe(RemovedLogsEvent{})
chain, _ := GenerateChain(nil, genesis, db, 2, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
if i == 1 { if i == 1 {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1) tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1)
if err != nil { if err != nil {
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
} }
@ -1003,7 +1006,7 @@ func TestLogReorgs(t *testing.T) {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
chain, _ = GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {}) chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
@ -1020,18 +1023,19 @@ func TestReorgSideEvent(t *testing.T) {
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)}) genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
signer = types.NewEIP155Signer(big.NewInt(1))
) )
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
replacementBlocks, _ := GenerateChain(nil, genesis, db, 4, func(i int, gen *BlockGen) { replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1) tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1)
if i == 2 { if i == 2 {
gen.OffsetTime(-1) gen.OffsetTime(-1)
} }
@ -1101,7 +1105,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
chain, _ := GenerateChain(nil, genesis, db, 10, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
for i, _ := range chain { for i, _ := range chain {
go func(block *types.Block) { go func(block *types.Block) {
@ -1128,3 +1132,105 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
blockchain.InsertChain(types.Blocks{chain[i]}) blockchain.InsertChain(types.Blocks{chain[i]})
} }
} }
func TestEIP155Transition(t *testing.T) {
// Configure and generate a sample block chain
var (
db, _ = ethdb.NewMemDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
config = &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
mux event.TypeMux
)
blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux)
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
err error
basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
}
)
switch i {
case 0:
tx, err = basicTx(types.HomesteadSigner{})
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
case 2:
tx, err = basicTx(types.HomesteadSigner{})
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
case 3:
tx, err = basicTx(types.HomesteadSigner{})
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
}
})
if _, err := blockchain.InsertChain(blocks); err != nil {
t.Fatal(err)
}
block := blockchain.GetBlockByNumber(1)
if block.Transactions()[0].Protected() {
t.Error("Expected block[0].txs[0] to not be replay protected")
}
block = blockchain.GetBlockByNumber(3)
if block.Transactions()[0].Protected() {
t.Error("Expected block[3].txs[0] to not be replay protected")
}
if !block.Transactions()[1].Protected() {
t.Error("Expected block[3].txs[1] to be replay protected")
}
if _, err := blockchain.InsertChain(blocks[4:]); err != nil {
t.Fatal(err)
}
// generate an invalid chain id transaction
config = &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
err error
basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
}
)
switch i {
case 0:
tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
if err != nil {
t.Fatal(err)
}
block.AddTx(tx)
}
})
errExp := "Invalid transaction chain id. Current chain id: 1 tx chain id: 2"
_, err := blockchain.InsertChain(blocks)
if err == nil {
t.Error("expected transaction chain id error")
} else if err.Error() != errExp {
t.Error("expected:", errExp, "got:", err)
}
}

View File

@ -35,8 +35,8 @@ import (
*/ */
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings. // MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
func MakeChainConfig() *ChainConfig { func MakeChainConfig() *params.ChainConfig {
return &ChainConfig{ return &params.ChainConfig{
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil, DAOForkBlock: nil,
DAOForkSupport: true, DAOForkSupport: true,
@ -73,6 +73,8 @@ type BlockGen struct {
txs []*types.Transaction txs []*types.Transaction
receipts []*types.Receipt receipts []*types.Receipt
uncles []*types.Header uncles []*types.Header
config *params.ChainConfig
} }
// SetCoinbase sets the coinbase of the generated block. // SetCoinbase sets the coinbase of the generated block.
@ -106,7 +108,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
b.SetCoinbase(common.Address{}) b.SetCoinbase(common.Address{})
} }
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -178,10 +180,10 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// Blocks created by GenerateChain do not contain valid proof of work // Blocks created by GenerateChain do not contain valid proof of work
// values. Inserting them into BlockChain requires use of FakePow or // values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation. // a similar non-validating proof of work implementation.
func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) { genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
// Mutate the state and block according to any hard-fork specs // Mutate the state and block according to any hard-fork specs
if config == nil { if config == nil {
@ -203,7 +205,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
gen(i, b) gen(i, b)
} }
AccumulateRewards(statedb, h, b.uncles) AccumulateRewards(statedb, h, b.uncles)
root, err := statedb.Commit() root, err := statedb.Commit(config.IsEIP158(h.Number))
if err != nil { if err != nil {
panic(fmt.Sprintf("state write error: %v", err)) panic(fmt.Sprintf("state write error: %v", err))
} }
@ -215,7 +217,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
if err != nil { if err != nil {
panic(err) panic(err)
} }
header := makeHeader(parent, statedb) header := makeHeader(config, parent, statedb)
block, receipt := genblock(i, header, statedb) block, receipt := genblock(i, header, statedb)
blocks[i] = block blocks[i] = block
receipts[i] = receipt receipts[i] = receipt
@ -224,7 +226,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
return blocks, receipts return blocks, receipts
} }
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.StateDB) *types.Header {
var time *big.Int var time *big.Int
if parent.Time() == nil { if parent.Time() == nil {
time = big.NewInt(10) time = big.NewInt(10)
@ -232,7 +234,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
} }
return &types.Header{ return &types.Header{
Root: state.IntermediateRoot(), Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
ParentHash: parent.Hash(), ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(), Coinbase: parent.Coinbase(),
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
@ -283,7 +285,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
// makeBlockChain creates a deterministic chain of blocks rooted at parent. // makeBlockChain creates a deterministic chain of blocks rooted at parent.
func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block { func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
blocks, _ := GenerateChain(nil, parent, db, n, func(i int, b *BlockGen) { blocks, _ := GenerateChain(params.TestChainConfig, parent, db, n, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
}) })
return blocks return blocks

View File

@ -39,25 +39,29 @@ func ExampleGenerateChain() {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
signer = types.HomesteadSigner{}
) )
chainConfig := &params.ChainConfig{
HomesteadBlock: new(big.Int),
}
// Ensure that key1 has some funds in the genesis block. // Ensure that key1 has some funds in the genesis block.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)}) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
// This call generates a chain of 5 blocks. The function runs for // This call generates a chain of 5 blocks. The function runs for
// each block and adds different features to gen based on the // each block and adds different features to gen based on the
// block index. // block index.
chain, _ := GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) { chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // In block 1, addr1 sends addr2 some ether.
tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(key1) tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, key1)
gen.AddTx(tx) gen.AddTx(tx)
case 1: case 1:
// In block 2, addr1 sends some more ether to addr2. // In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3. // addr2 passes it on to addr3.
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
gen.AddTx(tx1) gen.AddTx(tx1)
gen.AddTx(tx2) gen.AddTx(tx2)
case 2: case 2:
@ -77,7 +81,7 @@ func ExampleGenerateChain() {
// Import the chain. This runs all block validation rules. // Import the chain. This runs all block validation rules.
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, MakeChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, chainConfig, FakePow{}, evmux)
if i, err := blockchain.InsertChain(chain); err != nil { if i, err := blockchain.InsertChain(chain); err != nil {
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
return return

View File

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
@ -60,7 +61,7 @@ func TestPowVerification(t *testing.T) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -115,7 +116,7 @@ func testPowConcurrentVerification(t *testing.T, threads int) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -186,7 +187,7 @@ func testPowConcurrentAbortion(t *testing.T, threads int) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(nil, genesis, testdb, 1024, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {

View File

@ -1,63 +0,0 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
)
var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
// ChainConfig is the core config which determines the blockchain settings.
//
// ChainConfig is stored in the database on a per block basis. This means
// that any network, identified by its genesis block, can have its own
// set of configuration options.
type ChainConfig struct {
HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
HomesteadGasRepriceBlock *big.Int `json:"homesteadGasRepriceBlock"` // Homestead gas reprice switch block (nil = no fork)
HomesteadGasRepriceHash common.Hash `json:"homesteadGasRepriceHash"` // Homestead gas reprice switch block hash (fast sync aid)
VmConfig vm.Config `json:"-"`
}
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
if c.HomesteadBlock == nil || num == nil {
return false
}
return num.Cmp(c.HomesteadBlock) >= 0
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
func (c *ChainConfig) GasTable(num *big.Int) params.GasTable {
if c.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(c.HomesteadGasRepriceBlock) < 0 {
return params.GasTableHomestead
}
return params.GasTableHomesteadGasRepriceFork
}

View File

@ -33,7 +33,7 @@ import (
// with the fork specific extra-data set // with the fork specific extra-data set
// b) if the node is pro-fork, require blocks in the specific range to have the // b) if the node is pro-fork, require blocks in the specific range to have the
// unique extra-data set. // unique extra-data set.
func ValidateDAOHeaderExtraData(config *ChainConfig, header *types.Header) error { func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
// Short circuit validation if the node doesn't care about the DAO fork // Short circuit validation if the node doesn't care about the DAO fork
if config.DAOForkBlock == nil { if config.DAOForkBlock == nil {
return nil return nil

View File

@ -33,17 +33,17 @@ func TestDAOForkRangeExtradata(t *testing.T) {
// Generate a common prefix for both pro-forkers and non-forkers // Generate a common prefix for both pro-forkers and non-forkers
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis := WriteGenesisBlockForTesting(db) genesis := WriteGenesisBlockForTesting(db)
prefix, _ := GenerateChain(nil, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes // Create the concurrent, conflicting two nodes
proDb, _ := ethdb.NewMemDatabase() proDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(proDb) WriteGenesisBlockForTesting(proDb)
proConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true} proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux)) proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux))
conDb, _ := ethdb.NewMemDatabase() conDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(conDb) WriteGenesisBlockForTesting(conDb)
conConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false} conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux)) conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux))
if _, err := proBc.InsertChain(prefix); err != nil { if _, err := proBc.InsertChain(prefix); err != nil {

View File

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math/big" "math/big"
@ -28,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -59,6 +61,8 @@ var (
oldBlockNumPrefix = []byte("block-num-") oldBlockNumPrefix = []byte("block-num-")
oldBlockReceiptsPrefix = []byte("receipts-block-") oldBlockReceiptsPrefix = []byte("receipts-block-")
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
) )
// encodeBlockNumber encodes a block number as big endian uint64 // encodeBlockNumber encodes a block number as big endian uint64
@ -600,7 +604,7 @@ func WriteBlockChainVersion(db ethdb.Database, vsn int) {
} }
// WriteChainConfig writes the chain config settings to the database. // WriteChainConfig writes the chain config settings to the database.
func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) error { func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *params.ChainConfig) error {
// short circuit and ignore if nil config. GetChainConfig // short circuit and ignore if nil config. GetChainConfig
// will return a default. // will return a default.
if cfg == nil { if cfg == nil {
@ -616,13 +620,13 @@ func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) err
} }
// GetChainConfig will fetch the network settings based on the given hash. // GetChainConfig will fetch the network settings based on the given hash.
func GetChainConfig(db ethdb.Database, hash common.Hash) (*ChainConfig, error) { func GetChainConfig(db ethdb.Database, hash common.Hash) (*params.ChainConfig, error) {
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...)) jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
if len(jsonChainConfig) == 0 { if len(jsonChainConfig) == 0 {
return nil, ChainConfigNotFoundErr return nil, ChainConfigNotFoundErr
} }
var config ChainConfig var config params.ChainConfig
if err := json.Unmarshal(jsonChainConfig, &config); err != nil { if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
return nil, err return nil, err
} }

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -75,7 +76,7 @@ func TestCalcDifficulty(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
config := &ChainConfig{HomesteadBlock: big.NewInt(1150000)} config := &params.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
for name, test := range tests { for name, test := range tests {
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1)) number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty) diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
@ -562,7 +563,7 @@ func TestMipmapChain(t *testing.T) {
defer db.Close() defer db.Close()
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)}) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
chain, receipts := GenerateChain(nil, genesis, db, 1010, func(i int, gen *BlockGen) { chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -27,62 +27,17 @@ import (
// Call executes within the given contract // Call executes within the given contract
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
return ret, err
}
// CallCode executes the given address' code as the given contract address
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
callerAddr := caller.Address()
ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
return ret, err
}
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
callerAddr := caller.Address()
originAddr := env.Origin()
callerValue := caller.Value()
ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
return ret, err
}
// Create creates a new contract with the given code
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value)
// Here we get an error if we run into maximum stack depth,
// See: https://github.com/ethereum/yellowpaper/pull/131
// and YP definitions for CREATE instruction
if err != nil {
return nil, address, err
}
return ret, address, err
}
func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
evm := env.Vm()
// Depth check execution. Fail if we're trying to execute above the // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) { if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice) caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, vm.DepthError return nil, vm.DepthError
} }
if !env.CanTransfer(caller.Address(), value) { if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice) caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address())) return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
var createAccount bool
if address == nil {
// Create a new account on the state
nonce := env.Db().GetNonce(caller.Address())
env.Db().SetNonce(caller.Address(), nonce+1)
addr = crypto.CreateAddress(caller.Address(), nonce)
address = &addr
createAccount = true
} }
snapshotPreTransfer := env.SnapshotDatabase() snapshotPreTransfer := env.SnapshotDatabase()
@ -90,14 +45,15 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
from = env.Db().GetAccount(caller.Address()) from = env.Db().GetAccount(caller.Address())
to vm.Account to vm.Account
) )
if createAccount { if !env.Db().Exist(addr) {
to = env.Db().CreateAccount(*address) if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 {
} else { caller.ReturnGas(gas, gasPrice)
if !env.Db().Exist(*address) { return nil, nil
to = env.Db().CreateAccount(*address)
} else {
to = env.Db().GetAccount(*address)
} }
to = env.Db().CreateAccount(addr)
} else {
to = env.Db().GetAccount(addr)
} }
env.Transfer(from, to, value) env.Transfer(from, to, value)
@ -105,19 +61,106 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
// EVM. The contract is a scoped environment for this execution context // EVM. The contract is a scoped environment for this execution context
// only. // only.
contract := vm.NewContract(caller, to, value, gas, gasPrice) contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(codeAddr, codeHash, code) contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise() defer contract.Finalise()
ret, err = evm.Run(contract, input) ret, err = env.Vm().Run(contract, input)
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer)
}
return ret, err
}
// CallCode executes the given address' code as the given contract address
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, vm.DepthError
}
if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice)
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
var (
snapshotPreTransfer = env.SnapshotDatabase()
to = env.Db().GetAccount(caller.Address())
)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise()
ret, err = env.Vm().Run(contract, input)
if err != nil {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer)
}
return ret, err
}
// Create creates a new contract with the given code
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, vm.DepthError
}
if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
// Create a new account on the state
nonce := env.Db().GetNonce(caller.Address())
env.Db().SetNonce(caller.Address(), nonce+1)
snapshotPreTransfer := env.SnapshotDatabase()
var (
addr = crypto.CreateAddress(caller.Address(), nonce)
from = env.Db().GetAccount(caller.Address())
to = env.Db().CreateAccount(addr)
)
if env.ChainConfig().IsEIP158(env.BlockNumber()) {
env.Db().SetNonce(addr, 1)
}
env.Transfer(from, to, value)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
defer contract.Finalise()
ret, err = env.Vm().Run(contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned // if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not // calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled // be stored due to not enough gas set an error and let it be handled
// by the error checking condition below. // by the error checking condition below.
if err == nil && createAccount { if err == nil && !maxCodeSizeExceeded {
dataGas := big.NewInt(int64(len(ret))) dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas) dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) { if contract.UseGas(dataGas) {
env.Db().SetCode(*address, ret) env.Db().SetCode(addr, ret)
} else { } else {
err = vm.CodeStoreOutOfGasError err = vm.CodeStoreOutOfGasError
} }
@ -126,46 +169,45 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
// When an error was returned by the EVM or when setting the creation code // When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally // above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors. // when we're in homestead this also counts for code storage gas errors.
if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) { if maxCodeSizeExceeded ||
(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError)) {
contract.UseGas(contract.Gas) contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer) env.RevertToSnapshot(snapshotPreTransfer)
// Nothing should be returned when an error is thrown.
return nil, addr, err
} }
return ret, addr, err return ret, addr, err
} }
func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { // DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
evm := env.Vm() func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
// Depth check execution. Fail if we're trying to execute above the // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) { if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice) caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, vm.DepthError return nil, vm.DepthError
} }
snapshot := env.SnapshotDatabase() var (
snapshot = env.SnapshotDatabase()
var to vm.Account to = env.Db().GetAccount(caller.Address())
if !env.Db().Exist(*toAddr) { )
to = env.Db().CreateAccount(*toAddr)
} else {
to = env.Db().GetAccount(*toAddr)
}
// Iinitialise a new contract and make initialise the delegate values // Iinitialise a new contract and make initialise the delegate values
contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate() contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate()
contract.SetCallCode(codeAddr, codeHash, code) contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise() defer contract.Finalise()
ret, err = evm.Run(contract, input) ret, err = env.Vm().Run(contract, input)
if err != nil { if err != nil {
contract.UseGas(contract.Gas) contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshot) env.RevertToSnapshot(snapshot)
} }
return ret, addr, err return ret, err
} }
// generic transfer method // generic transfer method

View File

@ -43,7 +43,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
} }
var genesis struct { var genesis struct {
ChainConfig *ChainConfig `json:"config"` ChainConfig *params.ChainConfig `json:"config"`
Nonce string Nonce string
Timestamp string Timestamp string
ParentHash string ParentHash string
@ -73,7 +73,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value)) statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
} }
} }
root, stateBatch := statedb.CommitBatch() root, stateBatch := statedb.CommitBatch(false)
difficulty := common.String2Big(genesis.Difficulty) difficulty := common.String2Big(genesis.Difficulty)
block := types.NewBlock(&types.Header{ block := types.NewBlock(&types.Header{
@ -128,7 +128,7 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
statedb, _ := state.New(common.Hash{}, db) statedb, _ := state.New(common.Hash{}, db)
obj := statedb.GetOrNewStateObject(addr) obj := statedb.GetOrNewStateObject(addr)
obj.SetBalance(balance) obj.SetBalance(balance)
root, err := statedb.Commit() root, err := statedb.Commit(false)
if err != nil { if err != nil {
panic(fmt.Sprintf("cannot write state: %v", err)) panic(fmt.Sprintf("cannot write state: %v", err))
} }

View File

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
) )
@ -48,7 +49,7 @@ const (
// It is not thread safe either, the encapsulating chain structures should do // It is not thread safe either, the encapsulating chain structures should do
// the necessary mutex locking/unlocking. // the necessary mutex locking/unlocking.
type HeaderChain struct { type HeaderChain struct {
config *ChainConfig config *params.ChainConfig
chainDb ethdb.Database chainDb ethdb.Database
genesisHeader *types.Header genesisHeader *types.Header
@ -73,7 +74,7 @@ type getHeaderValidatorFn func() HeaderValidator
// getValidator should return the parent's validator // getValidator should return the parent's validator
// procInterrupt points to the parent's interrupt semaphore // procInterrupt points to the parent's interrupt semaphore
// wg points to the parent's shutdown wait group // wg points to the parent's shutdown wait group
func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) { func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
headerCache, _ := lru.New(headerCacheLimit) headerCache, _ := lru.New(headerCacheLimit)
tdCache, _ := lru.New(tdCacheLimit) tdCache, _ := lru.New(tdCacheLimit)
numberCache, _ := lru.New(numberCacheLimit) numberCache, _ := lru.New(numberCacheLimit)
@ -490,13 +491,13 @@ func (hc *HeaderChain) SetGenesis(head *types.Header) {
// //
// headerValidator implements HeaderValidator. // headerValidator implements HeaderValidator.
type headerValidator struct { type headerValidator struct {
config *ChainConfig config *params.ChainConfig
hc *HeaderChain // Canonical header chain hc *HeaderChain // Canonical header chain
Pow pow.PoW // Proof of work used for validating Pow pow.PoW // Proof of work used for validating
} }
// NewBlockValidator returns a new block validator which is safe for re-use // NewBlockValidator returns a new block validator which is safe for re-use
func NewHeaderValidator(config *ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator { func NewHeaderValidator(config *params.ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
return &headerValidator{ return &headerValidator{
config: config, config: config,
Pow: pow, Pow: pow,

View File

@ -91,6 +91,11 @@ type StateObject struct {
onDirty func(addr common.Address) // Callback method to mark a state object newly dirty onDirty func(addr common.Address) // Callback method to mark a state object newly dirty
} }
// empty returns whether the account is considered empty.
func (s *StateObject) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
}
// Account is the Ethereum consensus representation of accounts. // Account is the Ethereum consensus representation of accounts.
// These objects are stored in the main account trie. // These objects are stored in the main account trie.
type Account struct { type Account struct {
@ -221,8 +226,12 @@ func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) e
return err return err
} }
// AddBalance removes amount from c's balance.
// It is used to add funds to the destination account of a transfer.
func (c *StateObject) AddBalance(amount *big.Int) { func (c *StateObject) AddBalance(amount *big.Int) {
if amount.Cmp(common.Big0) == 0 { // EIP158: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
if amount.Cmp(common.Big0) == 0 && !c.empty() {
return return
} }
c.SetBalance(new(big.Int).Add(c.Balance(), amount)) c.SetBalance(new(big.Int).Add(c.Balance(), amount))
@ -232,6 +241,8 @@ func (c *StateObject) AddBalance(amount *big.Int) {
} }
} }
// SubBalance removes amount from c's balance.
// It is used to remove funds from the origin account of a transfer.
func (c *StateObject) SubBalance(amount *big.Int) { func (c *StateObject) SubBalance(amount *big.Int) {
if amount.Cmp(common.Big0) == 0 { if amount.Cmp(common.Big0) == 0 {
return return

View File

@ -48,7 +48,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
// write some of them to the trie // write some of them to the trie
s.state.updateStateObject(obj1) s.state.updateStateObject(obj1)
s.state.updateStateObject(obj2) s.state.updateStateObject(obj2)
s.state.Commit() s.state.Commit(false)
// check that dump contains the state objects that are in trie // check that dump contains the state objects that are in trie
got := string(s.state.Dump()) got := string(s.state.Dump())
@ -100,7 +100,7 @@ func TestNull(t *testing.T) {
//value := common.FromHex("0x823140710bf13990e4500136726d8b55") //value := common.FromHex("0x823140710bf13990e4500136726d8b55")
var value common.Hash var value common.Hash
state.SetState(address, common.Hash{}, value) state.SetState(address, common.Hash{}, value)
state.Commit() state.Commit(false)
value = state.GetState(address, common.Hash{}) value = state.GetState(address, common.Hash{})
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
t.Errorf("expected empty hash. got %x", value) t.Errorf("expected empty hash. got %x", value)
@ -160,7 +160,7 @@ func TestSnapshot2(t *testing.T) {
so0.deleted = false so0.deleted = false
state.setStateObject(so0) state.setStateObject(so0)
root, _ := state.Commit() root, _ := state.Commit(false)
state.Reset(root) state.Reset(root)
// and one with deleted == true // and one with deleted == true

View File

@ -213,6 +213,13 @@ func (self *StateDB) Exist(addr common.Address) bool {
return self.GetStateObject(addr) != nil return self.GetStateObject(addr) != nil
} }
// Empty returns whether the state object is either non-existant
// or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *StateDB) Empty(addr common.Address) bool {
so := self.GetStateObject(addr)
return so == nil || so.empty()
}
func (self *StateDB) GetAccount(addr common.Address) vm.Account { func (self *StateDB) GetAccount(addr common.Address) vm.Account {
return self.GetStateObject(addr) return self.GetStateObject(addr)
} }
@ -516,10 +523,10 @@ func (self *StateDB) GetRefund() *big.Int {
// IntermediateRoot computes the current root hash of the state trie. // IntermediateRoot computes the current root hash of the state trie.
// It is called in between transactions to get the root hash that // It is called in between transactions to get the root hash that
// goes into transaction receipts. // goes into transaction receipts.
func (s *StateDB) IntermediateRoot() common.Hash { func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
for addr, _ := range s.stateObjectsDirty { for addr, _ := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr] stateObject := s.stateObjects[addr]
if stateObject.suicided { if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
s.deleteStateObject(stateObject) s.deleteStateObject(stateObject)
} else { } else {
stateObject.updateRoot(s.db) stateObject.updateRoot(s.db)
@ -553,17 +560,17 @@ func (s *StateDB) DeleteSuicides() {
} }
// Commit commits all state changes to the database. // Commit commits all state changes to the database.
func (s *StateDB) Commit() (root common.Hash, err error) { func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
root, batch := s.CommitBatch() root, batch := s.CommitBatch(deleteEmptyObjects)
return root, batch.Write() return root, batch.Write()
} }
// CommitBatch commits all state changes to a write batch but does not // CommitBatch commits all state changes to a write batch but does not
// execute the batch. It is used to validate state changes against // execute the batch. It is used to validate state changes against
// the root hash stored in a block. // the root hash stored in a block.
func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) { func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
batch = s.db.NewBatch() batch = s.db.NewBatch()
root, _ = s.commit(batch) root, _ = s.commit(batch, deleteEmptyObjects)
glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads()) glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads())
return root, batch return root, batch
@ -575,16 +582,18 @@ func (s *StateDB) clearJournalAndRefund() {
s.refund = new(big.Int) s.refund = new(big.Int)
} }
func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) { func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
defer s.clearJournalAndRefund() defer s.clearJournalAndRefund()
// Commit objects to the trie. // Commit objects to the trie.
for addr, stateObject := range s.stateObjects { for addr, stateObject := range s.stateObjects {
if stateObject.suicided { _, isDirty := s.stateObjectsDirty[addr]
switch {
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
// If the object has been removed, don't bother syncing it // If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie. // and just mark it for deletion in the trie.
s.deleteStateObject(stateObject) s.deleteStateObject(stateObject)
} else if _, ok := s.stateObjectsDirty[addr]; ok { case isDirty:
// Write any contract code associated with the state object // Write any contract code associated with the state object
if stateObject.code != nil && stateObject.dirtyCode { if stateObject.code != nil && stateObject.dirtyCode {
if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil { if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {

View File

@ -51,7 +51,7 @@ func TestUpdateLeaks(t *testing.T) {
if i%3 == 0 { if i%3 == 0 {
state.SetCode(addr, []byte{i, i, i, i, i}) state.SetCode(addr, []byte{i, i, i, i, i})
} }
state.IntermediateRoot() state.IntermediateRoot(false)
} }
// Ensure that no data was leaked into the database // Ensure that no data was leaked into the database
for _, key := range db.Keys() { for _, key := range db.Keys() {
@ -86,7 +86,7 @@ func TestIntermediateLeaks(t *testing.T) {
modify(transState, common.Address{byte(i)}, i, 0) modify(transState, common.Address{byte(i)}, i, 0)
} }
// Write modifications to trie. // Write modifications to trie.
transState.IntermediateRoot() transState.IntermediateRoot(false)
// Overwrite all the data with new values in the transient database. // Overwrite all the data with new values in the transient database.
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
@ -95,10 +95,10 @@ func TestIntermediateLeaks(t *testing.T) {
} }
// Commit and cross check the databases. // Commit and cross check the databases.
if _, err := transState.Commit(); err != nil { if _, err := transState.Commit(false); err != nil {
t.Fatalf("failed to commit transition state: %v", err) t.Fatalf("failed to commit transition state: %v", err)
} }
if _, err := finalState.Commit(); err != nil { if _, err := finalState.Commit(false); err != nil {
t.Fatalf("failed to commit final state: %v", err) t.Fatalf("failed to commit final state: %v", err)
} }
for _, key := range finalDb.Keys() { for _, key := range finalDb.Keys() {

View File

@ -60,7 +60,7 @@ func makeTestState() (ethdb.Database, common.Hash, []*testAccount) {
state.updateStateObject(obj) state.updateStateObject(obj)
accounts = append(accounts, acc) accounts = append(accounts, acc)
} }
root, _ := state.Commit() root, _ := state.Commit(false)
// Return the generated state // Return the generated state
return db, root, accounts return db, root, accounts

View File

@ -17,6 +17,7 @@
package core package core
import ( import (
"fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -25,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
) )
var ( var (
@ -37,12 +39,12 @@ var (
// //
// StateProcessor implements Processor. // StateProcessor implements Processor.
type StateProcessor struct { type StateProcessor struct {
config *ChainConfig config *params.ChainConfig
bc *BlockChain bc *BlockChain
} }
// NewStateProcessor initialises a new StateProcessor. // NewStateProcessor initialises a new StateProcessor.
func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor { func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcessor {
return &StateProcessor{ return &StateProcessor{
config: config, config: config,
bc: bc, bc: bc,
@ -71,10 +73,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
if tx.Protected() && tx.ChainId().Cmp(p.config.ChainId) != 0 {
return nil, nil, nil, fmt.Errorf("Invalid transaction chain id. Current chain id: %v tx chain id: %v", p.config.ChainId, tx.ChainId())
}
statedb.StartRecord(tx.Hash(), block.Hash(), i) statedb.StartRecord(tx.Hash(), block.Hash(), i)
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
if err != nil { if err != nil {
return nil, nil, totalUsedGas, err return nil, nil, nil, err
} }
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
allLogs = append(allLogs, logs...) allLogs = append(allLogs, logs...)
@ -89,20 +95,24 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// //
// ApplyTransactions returns the generated receipts and vm logs during the // ApplyTransactions returns the generated receipts and vm logs during the
// execution of the state transition phase. // execution of the state transition phase.
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) { func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp) msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil {
return nil, nil, nil, err
}
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
// Update the state with pending changes // Update the state with pending changes
usedGas.Add(usedGas, gas) usedGas.Add(usedGas, gas)
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas) receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
receipt.TxHash = tx.Hash() receipt.TxHash = tx.Hash()
receipt.GasUsed = new(big.Int).Set(gas) receipt.GasUsed = new(big.Int).Set(gas)
if MessageCreatesContract(tx) { if MessageCreatesContract(msg) {
from, _ := tx.From() receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce())
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
} }
logs := statedb.GetLogs(tx.Hash()) logs := statedb.GetLogs(tx.Hash())

View File

@ -62,8 +62,8 @@ type StateTransition struct {
// Message represents a message sent to a contract. // Message represents a message sent to a contract.
type Message interface { type Message interface {
From() (common.Address, error) From() common.Address
FromFrontier() (common.Address, error) //FromFrontier() (common.Address, error)
To() *common.Address To() *common.Address
GasPrice() *big.Int GasPrice() *big.Int
@ -134,23 +134,12 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
return ret, gasUsed, err return ret, gasUsed, err
} }
func (self *StateTransition) from() (vm.Account, error) { func (self *StateTransition) from() vm.Account {
var ( f := self.msg.From()
f common.Address
err error
)
if self.env.RuleSet().IsHomestead(self.env.BlockNumber()) {
f, err = self.msg.From()
} else {
f, err = self.msg.FromFrontier()
}
if err != nil {
return nil, err
}
if !self.state.Exist(f) { if !self.state.Exist(f) {
return self.state.CreateAccount(f), nil return self.state.CreateAccount(f)
} }
return self.state.GetAccount(f), nil return self.state.GetAccount(f)
} }
func (self *StateTransition) to() vm.Account { func (self *StateTransition) to() vm.Account {
@ -185,14 +174,11 @@ func (self *StateTransition) buyGas() error {
mgas := self.msg.Gas() mgas := self.msg.Gas()
mgval := new(big.Int).Mul(mgas, self.gasPrice) mgval := new(big.Int).Mul(mgas, self.gasPrice)
sender, err := self.from() sender := self.from()
if err != nil {
return err
}
if sender.Balance().Cmp(mgval) < 0 { if sender.Balance().Cmp(mgval) < 0 {
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance()) return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
} }
if err = self.gp.SubGas(mgas); err != nil { if err := self.gp.SubGas(mgas); err != nil {
return err return err
} }
self.addGas(mgas) self.addGas(mgas)
@ -203,10 +189,7 @@ func (self *StateTransition) buyGas() error {
func (self *StateTransition) preCheck() (err error) { func (self *StateTransition) preCheck() (err error) {
msg := self.msg msg := self.msg
sender, err := self.from() sender := self.from()
if err != nil {
return err
}
// Make sure this transaction's nonce is correct // Make sure this transaction's nonce is correct
if msg.CheckNonce() { if msg.CheckNonce() {
@ -232,9 +215,9 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
return return
} }
msg := self.msg msg := self.msg
sender, _ := self.from() // err checked in preCheck sender := self.from() // err checked in preCheck
homestead := self.env.RuleSet().IsHomestead(self.env.BlockNumber()) homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber())
contractCreation := MessageCreatesContract(msg) contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas // Pay intrinsic gas
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
@ -282,7 +265,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
func (self *StateTransition) refundGas() { func (self *StateTransition) refundGas() {
// Return eth for remaining gas to the sender account, // Return eth for remaining gas to the sender account,
// exchanged at the original rate. // exchanged at the original rate.
sender, _ := self.from() // err already checked sender := self.from() // err already checked
remaining := new(big.Int).Mul(self.gas, self.gasPrice) remaining := new(big.Int).Mul(self.gas, self.gasPrice)
sender.AddBalance(remaining) sender.AddBalance(remaining)

View File

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"gopkg.in/karalabe/cookiejar.v2/collections/prque" "gopkg.in/karalabe/cookiejar.v2/collections/prque"
) )
@ -83,7 +84,7 @@ type stateFn func() (*state.StateDB, error)
// current state) and future transactions. Transactions move between those // current state) and future transactions. Transactions move between those
// two states over time as they are received and processed. // two states over time as they are received and processed.
type TxPool struct { type TxPool struct {
config *ChainConfig config *params.ChainConfig
currentState stateFn // The state function which will allow us to do some pre checks currentState stateFn // The state function which will allow us to do some pre checks
pendingState *state.ManagedState pendingState *state.ManagedState
gasLimit func() *big.Int // The current gas limit function callback gasLimit func() *big.Int // The current gas limit function callback
@ -91,6 +92,7 @@ type TxPool struct {
eventMux *event.TypeMux eventMux *event.TypeMux
events event.Subscription events event.Subscription
localTx *txSet localTx *txSet
signer types.Signer
mu sync.RWMutex mu sync.RWMutex
pending map[common.Address]*txList // All currently processable transactions pending map[common.Address]*txList // All currently processable transactions
@ -104,9 +106,10 @@ type TxPool struct {
homestead bool homestead bool
} }
func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
pool := &TxPool{ pool := &TxPool{
config: config, config: config,
signer: types.NewEIP155Signer(config.ChainId),
pending: make(map[common.Address]*txList), pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList), queue: make(map[common.Address]*txList),
all: make(map[common.Hash]*types.Transaction), all: make(map[common.Hash]*types.Transaction),
@ -138,8 +141,10 @@ func (pool *TxPool) eventLoop() {
switch ev := ev.Data.(type) { switch ev := ev.Data.(type) {
case ChainHeadEvent: case ChainHeadEvent:
pool.mu.Lock() pool.mu.Lock()
if ev.Block != nil && pool.config.IsHomestead(ev.Block.Number()) { if ev.Block != nil {
pool.homestead = true if pool.config.IsHomestead(ev.Block.Number()) {
pool.homestead = true
}
} }
pool.resetState() pool.resetState()
@ -271,7 +276,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return err return err
} }
from, err := tx.From() from, err := types.Sender(pool.signer, tx)
if err != nil { if err != nil {
return ErrInvalidSender return ErrInvalidSender
} }
@ -306,7 +311,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return ErrInsufficientFunds return ErrInsufficientFunds
} }
intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), pool.homestead) intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
if tx.Gas().Cmp(intrGas) < 0 { if tx.Gas().Cmp(intrGas) < 0 {
return ErrIntrinsicGas return ErrIntrinsicGas
} }
@ -335,7 +340,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
if to := tx.To(); to != nil { if to := tx.To(); to != nil {
rcpt = common.Bytes2Hex(to[:4]) rcpt = common.Bytes2Hex(to[:4])
} }
from, _ := tx.From() // from already verified during tx validation from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation
glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash) glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash)
} }
return nil return nil
@ -346,7 +351,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
// Note, this method assumes the pool lock is held! // Note, this method assumes the pool lock is held!
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) { func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
// Try to insert the transaction into the future queue // Try to insert the transaction into the future queue
from, _ := tx.From() // already validated from, _ := types.Sender(pool.signer, tx) // already validated
if pool.queue[from] == nil { if pool.queue[from] == nil {
pool.queue[from] = newTxList(false) pool.queue[from] = newTxList(false)
} }
@ -458,7 +463,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
if !ok { if !ok {
return return
} }
addr, _ := tx.From() // already validated during insertion addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
// Remove it from the list of known transactions // Remove it from the list of known transactions
delete(pool.all, hash) delete(pool.all, hash)

View File

@ -32,7 +32,7 @@ import (
) )
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(key) tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
return tx return tx
} }
@ -47,6 +47,10 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
return newPool, key return newPool, key
} }
func deriveSender(tx *types.Transaction) (common.Address, error) {
return types.Sender(types.HomesteadSigner{}, tx)
}
func TestInvalidTransactions(t *testing.T) { func TestInvalidTransactions(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
@ -55,7 +59,7 @@ func TestInvalidTransactions(t *testing.T) {
t.Error("expected", ErrNonExistentAccount) t.Error("expected", ErrNonExistentAccount)
} }
from, _ := tx.From() from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1)) currentState.AddBalance(from, big.NewInt(1))
if err := pool.Add(tx); err != ErrInsufficientFunds { if err := pool.Add(tx); err != ErrInsufficientFunds {
@ -90,7 +94,7 @@ func TestInvalidTransactions(t *testing.T) {
func TestTransactionQueue(t *testing.T) { func TestTransactionQueue(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx := transaction(0, big.NewInt(100), key) tx := transaction(0, big.NewInt(100), key)
from, _ := tx.From() from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1000)) currentState.AddBalance(from, big.NewInt(1000))
pool.enqueueTx(tx.Hash(), tx) pool.enqueueTx(tx.Hash(), tx)
@ -101,7 +105,7 @@ func TestTransactionQueue(t *testing.T) {
} }
tx = transaction(1, big.NewInt(100), key) tx = transaction(1, big.NewInt(100), key)
from, _ = tx.From() from, _ = deriveSender(tx)
currentState.SetNonce(from, 2) currentState.SetNonce(from, 2)
pool.enqueueTx(tx.Hash(), tx) pool.enqueueTx(tx.Hash(), tx)
pool.promoteExecutables() pool.promoteExecutables()
@ -117,7 +121,7 @@ func TestTransactionQueue(t *testing.T) {
tx1 := transaction(0, big.NewInt(100), key) tx1 := transaction(0, big.NewInt(100), key)
tx2 := transaction(10, big.NewInt(100), key) tx2 := transaction(10, big.NewInt(100), key)
tx3 := transaction(11, big.NewInt(100), key) tx3 := transaction(11, big.NewInt(100), key)
from, _ = tx1.From() from, _ = deriveSender(tx1)
currentState, _ = pool.currentState() currentState, _ = pool.currentState()
currentState.AddBalance(from, big.NewInt(1000)) currentState.AddBalance(from, big.NewInt(1000))
pool.enqueueTx(tx1.Hash(), tx1) pool.enqueueTx(tx1.Hash(), tx1)
@ -137,7 +141,7 @@ func TestTransactionQueue(t *testing.T) {
func TestRemoveTx(t *testing.T) { func TestRemoveTx(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx := transaction(0, big.NewInt(100), key) tx := transaction(0, big.NewInt(100), key)
from, _ := tx.From() from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1)) currentState.AddBalance(from, big.NewInt(1))
@ -161,8 +165,8 @@ func TestRemoveTx(t *testing.T) {
func TestNegativeValue(t *testing.T) { func TestNegativeValue(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key) tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
from, _ := tx.From() from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1)) currentState.AddBalance(from, big.NewInt(1))
if err := pool.Add(tx); err != ErrNegativeValue { if err := pool.Add(tx); err != ErrNegativeValue {
@ -209,9 +213,10 @@ func TestTransactionDoubleNonce(t *testing.T) {
} }
resetState() resetState()
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(key) signer := types.HomesteadSigner{}
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(key) tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key)
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(key) tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key)
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key)
// Add the first two transaction, ensure higher priced stays only // Add the first two transaction, ensure higher priced stays only
if err := pool.add(tx1); err != nil { if err := pool.add(tx1); err != nil {
@ -287,7 +292,7 @@ func TestNonceRecovery(t *testing.T) {
func TestRemovedTxEvent(t *testing.T) { func TestRemovedTxEvent(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx := transaction(0, big.NewInt(1000000), key) tx := transaction(0, big.NewInt(1000000), key)
from, _ := tx.From() from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1000000000000)) currentState.AddBalance(from, big.NewInt(1000000000000))
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
@ -305,7 +310,7 @@ func TestRemovedTxEvent(t *testing.T) {
func TestTransactionDropping(t *testing.T) { func TestTransactionDropping(t *testing.T) {
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000)) state.AddBalance(account, big.NewInt(1000))
@ -369,7 +374,7 @@ func TestTransactionDropping(t *testing.T) {
func TestTransactionPostponing(t *testing.T) { func TestTransactionPostponing(t *testing.T) {
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000)) state.AddBalance(account, big.NewInt(1000))
@ -443,7 +448,7 @@ func TestTransactionPostponing(t *testing.T) {
func TestTransactionQueueAccountLimiting(t *testing.T) { func TestTransactionQueueAccountLimiting(t *testing.T) {
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -531,7 +536,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -555,7 +560,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
func TestTransactionPendingLimiting(t *testing.T) { func TestTransactionPendingLimiting(t *testing.T) {
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -585,7 +590,7 @@ func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLi
func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
// Add a batch of transactions to a pool one by one // Add a batch of transactions to a pool one by one
pool1, key1 := setupTxPool() pool1, key1 := setupTxPool()
account1, _ := transaction(0, big.NewInt(0), key1).From() account1, _ := deriveSender(transaction(0, big.NewInt(0), key1))
state1, _ := pool1.currentState() state1, _ := pool1.currentState()
state1.AddBalance(account1, big.NewInt(1000000)) state1.AddBalance(account1, big.NewInt(1000000))
@ -596,7 +601,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
} }
// Add a batch of transactions to a pool in one big batch // Add a batch of transactions to a pool in one big batch
pool2, key2 := setupTxPool() pool2, key2 := setupTxPool()
account2, _ := transaction(0, big.NewInt(0), key2).From() account2, _ := deriveSender(transaction(0, big.NewInt(0), key2))
state2, _ := pool2.currentState() state2, _ := pool2.currentState()
state2.AddBalance(account2, big.NewInt(1000000)) state2.AddBalance(account2, big.NewInt(1000000))
@ -717,7 +722,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1
func benchmarkPendingDemotion(b *testing.B, size int) { func benchmarkPendingDemotion(b *testing.B, size int) {
// Add a batch of transactions to a pool one by one // Add a batch of transactions to a pool one by one
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -741,7 +746,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1
func benchmarkFuturePromotion(b *testing.B, size int) { func benchmarkFuturePromotion(b *testing.B, size int) {
// Add a batch of transactions to a pool one by one // Add a batch of transactions to a pool one by one
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -760,7 +765,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
func BenchmarkPoolInsert(b *testing.B) { func BenchmarkPoolInsert(b *testing.B) {
// Generate a batch of transactions to enqueue into the pool // Generate a batch of transactions to enqueue into the pool
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
@ -783,7 +788,7 @@ func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 1
func benchmarkPoolBatchInsert(b *testing.B, size int) { func benchmarkPoolBatchInsert(b *testing.B, size int) {
// Generate a batch of transactions to enqueue into the pool // Generate a batch of transactions to enqueue into the pool
pool, key := setupTxPool() pool, key := setupTxPool()
account, _ := transaction(0, big.NewInt(0), key).From() account, _ := deriveSender(transaction(0, big.NewInt(0), key))
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))

View File

@ -18,6 +18,7 @@ package types
import ( import (
"bytes" "bytes"
"fmt"
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
@ -51,7 +52,11 @@ func TestBlockEncoding(t *testing.T) {
check("Size", block.Size(), common.StorageSize(len(blockEnc))) check("Size", block.Size(), common.StorageSize(len(blockEnc)))
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
tx1, _ = tx1.WithSignature(common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
fmt.Println(block.Transactions()[0].Hash())
fmt.Println(tx1.data)
fmt.Println(tx1.Hash())
check("len(Transactions)", len(block.Transactions()), 1) check("len(Transactions)", len(block.Transactions()), 1)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash()) check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())

View File

@ -97,10 +97,12 @@ var unmarshalTransactionTests = map[string]struct {
wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"), wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"),
wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"), wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"),
}, },
/* TODO skipping this test as this type can not be tested with the current signing approach
"bad signature fields": { "bad signature fields": {
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
wantError: ErrInvalidSig, wantError: ErrInvalidSig,
}, },
*/
"missing signature v": { "missing signature v": {
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
wantError: errMissingTxSignatureFields, wantError: errMissingTxSignatureFields,
@ -122,11 +124,12 @@ func TestUnmarshalTransaction(t *testing.T) {
if !checkError(t, name, err, test.wantError) { if !checkError(t, name, err, test.wantError) {
continue continue
} }
if tx.Hash() != test.wantHash { if tx.Hash() != test.wantHash {
t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash) t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash)
continue continue
} }
from, err := tx.From() from, err := Sender(HomesteadSigner{}, tx)
if err != nil { if err != nil {
t.Errorf("test %q: From error %v", name, err) t.Errorf("test %q: From error %v", name, err)
} }

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -36,8 +37,18 @@ var ErrInvalidSig = errors.New("invalid transaction v, r, s values")
var ( var (
errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields") errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields")
errMissingTxFields = errors.New("missing required JSON transaction fields") errMissingTxFields = errors.New("missing required JSON transaction fields")
errNoSigner = errors.New("missing signing methods")
) )
// deriveSigner makes a *best* guess about which signer to use.
func deriveSigner(V *big.Int) Signer {
if V.BitLen() > 0 && isProtectedV(V) {
return EIP155Signer{chainId: deriveChainId(V)}
} else {
return HomesteadSigner{}
}
}
type Transaction struct { type Transaction struct {
data txdata data txdata
// caches // caches
@ -52,7 +63,7 @@ type txdata struct {
Recipient *common.Address `rlp:"nil"` // nil means contract creation Recipient *common.Address `rlp:"nil"` // nil means contract creation
Amount *big.Int Amount *big.Int
Payload []byte Payload []byte
V byte // signature V *big.Int // signature
R, S *big.Int // signature R, S *big.Int // signature
} }
@ -64,40 +75,31 @@ type jsonTransaction struct {
Recipient *common.Address `json:"to"` Recipient *common.Address `json:"to"`
Amount *hexBig `json:"value"` Amount *hexBig `json:"value"`
Payload *hexBytes `json:"input"` Payload *hexBytes `json:"input"`
V *hexUint64 `json:"v"` V *hexBig `json:"v"`
R *hexBig `json:"r"` R *hexBig `json:"r"`
S *hexBig `json:"s"` S *hexBig `json:"s"`
} }
// NewContractCreation creates a new transaction with no recipient. func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
if len(data) > 0 {
data = common.CopyBytes(data)
}
return &Transaction{data: txdata{
AccountNonce: nonce,
Recipient: nil,
Amount: new(big.Int).Set(amount),
GasLimit: new(big.Int).Set(gasLimit),
Price: new(big.Int).Set(gasPrice),
Payload: data,
R: new(big.Int),
S: new(big.Int),
}}
} }
// NewTransaction creates a new transaction with the given fields. func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
}
func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
if len(data) > 0 { if len(data) > 0 {
data = common.CopyBytes(data) data = common.CopyBytes(data)
} }
d := txdata{ d := txdata{
AccountNonce: nonce, AccountNonce: nonce,
Recipient: &to, Recipient: to,
Payload: data, Payload: data,
Amount: new(big.Int), Amount: new(big.Int),
GasLimit: new(big.Int), GasLimit: new(big.Int),
Price: new(big.Int), Price: new(big.Int),
V: new(big.Int),
R: new(big.Int), R: new(big.Int),
S: new(big.Int), S: new(big.Int),
} }
@ -110,9 +112,42 @@ func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice
if gasPrice != nil { if gasPrice != nil {
d.Price.Set(gasPrice) d.Price.Set(gasPrice)
} }
return &Transaction{data: d} return &Transaction{data: d}
} }
func pickSigner(rules params.Rules) Signer {
var signer Signer
switch {
case rules.IsEIP155:
signer = NewEIP155Signer(rules.ChainId)
case rules.IsHomestead:
signer = HomesteadSigner{}
default:
signer = FrontierSigner{}
}
return signer
}
// ChainId returns which chain id this transaction was signed for (if at all)
func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V)
}
// Protected returns whether the transaction is pretected from replay protection
func (tx *Transaction) Protected() bool {
return isProtectedV(tx.data.V)
}
func isProtectedV(V *big.Int) bool {
if V.BitLen() <= 8 {
v := V.Uint64()
return v != 27 && v != 28
}
// anything not 27 or 28 are considered unprotected
return true
}
// DecodeRLP implements rlp.Encoder // DecodeRLP implements rlp.Encoder
func (tx *Transaction) EncodeRLP(w io.Writer) error { func (tx *Transaction) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &tx.data) return rlp.Encode(w, &tx.data)
@ -125,12 +160,13 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
if err == nil { if err == nil {
tx.size.Store(common.StorageSize(rlp.ListSize(size))) tx.size.Store(common.StorageSize(rlp.ListSize(size)))
} }
return err return err
} }
// MarshalJSON encodes transactions into the web3 RPC response block format. // MarshalJSON encodes transactions into the web3 RPC response block format.
func (tx *Transaction) MarshalJSON() ([]byte, error) { func (tx *Transaction) MarshalJSON() ([]byte, error) {
hash, v := tx.Hash(), uint64(tx.data.V) hash := tx.Hash()
return json.Marshal(&jsonTransaction{ return json.Marshal(&jsonTransaction{
Hash: &hash, Hash: &hash,
@ -140,7 +176,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
Recipient: tx.data.Recipient, Recipient: tx.data.Recipient,
Amount: (*hexBig)(tx.data.Amount), Amount: (*hexBig)(tx.data.Amount),
Payload: (*hexBytes)(&tx.data.Payload), Payload: (*hexBytes)(&tx.data.Payload),
V: (*hexUint64)(&v), V: (*hexBig)(tx.data.V),
R: (*hexBig)(tx.data.R), R: (*hexBig)(tx.data.R),
S: (*hexBig)(tx.data.S), S: (*hexBig)(tx.data.S),
}) })
@ -159,9 +195,17 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
if dec.V == nil || dec.R == nil || dec.S == nil { if dec.V == nil || dec.R == nil || dec.S == nil {
return errMissingTxSignatureFields return errMissingTxSignatureFields
} }
if !crypto.ValidateSignatureValues(byte(*dec.V), (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
var V byte
if isProtectedV((*big.Int)(dec.V)) {
V = normaliseV(NewEIP155Signer(deriveChainId((*big.Int)(dec.V))), (*big.Int)(dec.V))
} else {
V = byte(((*big.Int)(dec.V)).Uint64())
}
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
return ErrInvalidSig return ErrInvalidSig
} }
if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil { if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
return errMissingTxFields return errMissingTxFields
} }
@ -175,7 +219,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
GasLimit: (*big.Int)(dec.GasLimit), GasLimit: (*big.Int)(dec.GasLimit),
Price: (*big.Int)(dec.Price), Price: (*big.Int)(dec.Price),
Payload: *dec.Payload, Payload: *dec.Payload,
V: byte(*dec.V), V: (*big.Int)(dec.V),
R: (*big.Int)(dec.R), R: (*big.Int)(dec.R),
S: (*big.Int)(dec.S), S: (*big.Int)(dec.S),
} }
@ -211,15 +255,8 @@ func (tx *Transaction) Hash() common.Hash {
// SigHash returns the hash to be signed by the sender. // SigHash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction. // It does not uniquely identify the transaction.
func (tx *Transaction) SigHash() common.Hash { func (tx *Transaction) SigHash(signer Signer) common.Hash {
return rlpHash([]interface{}{ return signer.Hash(tx)
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Recipient,
tx.data.Amount,
tx.data.Payload,
})
} }
func (tx *Transaction) Size() common.StorageSize { func (tx *Transaction) Size() common.StorageSize {
@ -232,6 +269,7 @@ func (tx *Transaction) Size() common.StorageSize {
return common.StorageSize(c) return common.StorageSize(c)
} }
/*
// From returns the address derived from the signature (V, R, S) using secp256k1 // From returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect // elliptic curve and an error if it failed deriving or upon an incorrect
// signature. // signature.
@ -247,32 +285,15 @@ func (tx *Transaction) Size() common.StorageSize {
// both txs before and after the first homestead block. Signatures // both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier) // valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) From() (common.Address, error) { func (tx *Transaction) From() (common.Address, error) {
return doFrom(tx, true) if tx.signer == nil {
} return common.Address{}, errNoSigner
}
// FromFrontier returns the address derived from the signature (V, R, S) using
// secp256k1 elliptic curve and an error if it failed deriving or upon an
// incorrect signature.
//
// FromFrantier uses the frontier consensus rules to determine whether the
// signature is valid.
//
// FromFrontier caches the address, allowing it to be used regardless of
// Frontier / Homestead. however, the first time called it runs
// signature validations, so we need two versions. This makes it
// easier to ensure backwards compatibility of things like package rpc
// where eth_getblockbynumber uses tx.From() and needs to work for
// both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) FromFrontier() (common.Address, error) {
return doFrom(tx, false)
}
func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
if from := tx.from.Load(); from != nil { if from := tx.from.Load(); from != nil {
return from.(common.Address), nil return from.(common.Address), nil
} }
pubkey, err := tx.publicKey(homestead)
pubkey, err := tx.signer.PublicKey(tx)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
@ -282,6 +303,51 @@ func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
return addr, nil return addr, nil
} }
// SignatureValues returns the ECDSA signature values contained in the transaction.
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int, err error) {
if tx.signer == nil {
return 0, nil, nil,errNoSigner
}
return normaliseV(tx.signer, tx.data.V), new(big.Int).Set(tx.data.R),new(big.Int).Set(tx.data.S), nil
}
*/
// AsMessage returns the transaction as a core.Message.
//
// AsMessage requires a signer to derive the sender.
//
// XXX Rename message to something less arbitrary?
func (tx *Transaction) AsMessage(s Signer) (Message, error) {
msg := Message{
nonce: tx.data.AccountNonce,
price: new(big.Int).Set(tx.data.Price),
gasLimit: new(big.Int).Set(tx.data.GasLimit),
to: tx.data.Recipient,
amount: tx.data.Amount,
data: tx.data.Payload,
}
var err error
msg.from, err = Sender(s, tx)
return msg, err
}
// SignECDSA signs the transaction using the given signer and private key
//
// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should
// we keep this?
func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
return signer.SignECDSA(tx, prv)
}
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
return signer.WithSignature(tx, sig)
}
// Cost returns amount + gasprice * gaslimit. // Cost returns amount + gasprice * gaslimit.
func (tx *Transaction) Cost() *big.Int { func (tx *Transaction) Cost() *big.Int {
total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit) total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit)
@ -289,61 +355,18 @@ func (tx *Transaction) Cost() *big.Int {
return total return total
} }
// SignatureValues returns the ECDSA signature values contained in the transaction. func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) { return tx.data.V, tx.data.R, tx.data.S
return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
}
func (tx *Transaction) publicKey(homestead bool) ([]byte, error) {
if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S, homestead) {
return nil, ErrInvalidSig
}
// encode the signature in uncompressed format
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = tx.data.V - 27
// recover the public key from the signature
hash := tx.SigHash()
pub, err := crypto.Ecrecover(hash[:], sig)
if err != nil {
return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
return nil, errors.New("invalid public key")
}
return pub, nil
}
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
}
cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = sig[64]
return cpy, nil
}
func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) (*Transaction, error) {
h := tx.SigHash()
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return tx.WithSignature(sig)
} }
func (tx *Transaction) String() string { func (tx *Transaction) String() string {
// make a best guess about the signer and use that to derive
// the sender.
signer := deriveSigner(tx.data.V)
var from, to string var from, to string
if f, err := tx.From(); err != nil { if f, err := Sender(signer, tx); err != nil { // derive but don't cache
from = "[invalid sender]" from = "[invalid sender: invalid sig]"
} else { } else {
from = fmt.Sprintf("%x", f[:]) from = fmt.Sprintf("%x", f[:])
} }
@ -485,8 +508,9 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
// Shift replaces the current best head with the next one from the same account. // Shift replaces the current best head with the next one from the same account.
func (t *TransactionsByPriceAndNonce) Shift() { func (t *TransactionsByPriceAndNonce) Shift() {
acc, _ := t.heads[0].From() // we only sort valid txs so this cannot fail signer := deriveSigner(t.heads[0].data.V)
// derive signer but don't cache.
acc, _ := Sender(signer, t.heads[0]) // we only sort valid txs so this cannot fail
if txs, ok := t.txs[acc]; ok && len(txs) > 0 { if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
t.heads[0], t.txs[acc] = txs[0], txs[1:] t.heads[0], t.txs[acc] = txs[0], txs[1:]
heap.Fix(&t.heads, 0) heap.Fix(&t.heads, 0)
@ -501,3 +525,35 @@ func (t *TransactionsByPriceAndNonce) Shift() {
func (t *TransactionsByPriceAndNonce) Pop() { func (t *TransactionsByPriceAndNonce) Pop() {
heap.Pop(&t.heads) heap.Pop(&t.heads)
} }
// Message is a fully derived transaction and implements core.Message
//
// NOTE: In a future PR this will be removed.
type Message struct {
to *common.Address
from common.Address
nonce uint64
amount, price, gasLimit *big.Int
data []byte
}
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount, gasLimit, price *big.Int, data []byte) Message {
return Message{
from: from,
to: to,
nonce: nonce,
amount: amount,
price: price,
gasLimit: gasLimit,
data: data,
}
}
func (m Message) From() common.Address { return m.from }
func (m Message) To() *common.Address { return m.to }
func (m Message) GasPrice() *big.Int { return m.price }
func (m Message) Value() *big.Int { return m.amount }
func (m Message) Gas() *big.Int { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data }
func (m Message) CheckNonce() bool { return true }

View File

@ -0,0 +1,340 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
// sigCache is used to cache the derived sender and contains
// the signer used to derive it.
type sigCache struct {
signer Signer
from common.Address
}
// MakeSigner returns a Signer based on the given chain config and block number.
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId)
case config.IsHomestead(blockNumber):
signer = HomesteadSigner{}
default:
signer = FrontierSigner{}
}
return signer
}
// SignECDSA signs the transaction using the given signer and private key
func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return s.WithSignature(tx, sig)
}
// Sender derives the sender from the tx using the signer derivation
// functions.
// Sender returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect
// signature.
//
// Sender may cache the address, allowing it to be used regardless of
// signing method. The cache is invalidated if the cached signer does
// not match the signer used in the current call.
func Sender(signer Signer, tx *Transaction) (common.Address, error) {
if sc := tx.from.Load(); sc != nil {
sigCache := sc.(sigCache)
// If the signer used to derive from in a previous
// call is not the same as used current, invalidate
// the cache.
if reflect.TypeOf(sigCache.signer) == reflect.TypeOf(signer) {
return sigCache.from, nil
}
}
pubkey, err := signer.PublicKey(tx)
if err != nil {
return common.Address{}, err
}
var addr common.Address
copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
tx.from.Store(sigCache{signer: signer, from: addr})
return addr, nil
}
// SignatureValues returns the ECDSA signature values contained in the transaction.
func SignatureValues(signer Signer, tx *Transaction) (v byte, r *big.Int, s *big.Int) {
return normaliseV(signer, tx.data.V), new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
}
type Signer interface {
// Hash returns the rlp encoded hash for signatures
Hash(tx *Transaction) common.Hash
// PubilcKey returns the public key derived from the signature
PublicKey(tx *Transaction) ([]byte, error)
// SignECDSA signs the transaction with the given and returns a copy of the tx
SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error)
// WithSignature returns a copy of the transaction with the given signature
WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
}
// EIP155Transaction implements TransactionInterface using the
// EIP155 rules
type EIP155Signer struct {
HomesteadSigner
chainId, chainIdMul *big.Int
}
func NewEIP155Signer(chainId *big.Int) EIP155Signer {
return EIP155Signer{
chainId: chainId,
chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
}
}
func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
return SignECDSA(s, tx, prv)
}
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
// if the transaction is not protected fall back to homestead signer
if !tx.Protected() {
return (HomesteadSigner{}).PublicKey(tx)
}
V := normaliseV(s, tx.data.V)
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
return nil, ErrInvalidSig
}
// encode the signature in uncompressed format
R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(R):32], R)
copy(sig[64-len(S):64], S)
sig[64] = V - 27
// recover the public key from the signature
hash := s.Hash(tx)
pub, err := crypto.Ecrecover(hash[:], sig)
if err != nil {
return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
return nil, errors.New("invalid public key")
}
return pub, nil
}
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
if s.chainId.BitLen() > 0 {
cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35))
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
}
return cpy, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Recipient,
tx.data.Amount,
tx.data.Payload,
s.chainId, uint(0), uint(0),
})
}
func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return s.WithSignature(tx, sig)
}
// HomesteadTransaction implements TransactionInterface using the
// homestead rules.
type HomesteadSigner struct{ FrontierSigner }
// WithSignature returns a new transaction with the given snature.
// This snature needs to be formatted as described in the yellow paper (v+27).
func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
return cpy, nil
}
func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := hs.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return hs.WithSignature(tx, sig)
}
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
if tx.data.V.BitLen() > 8 {
return nil, ErrInvalidSig
}
V := byte(tx.data.V.Uint64())
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
return nil, ErrInvalidSig
}
// encode the snature in uncompressed format
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V - 27
// recover the public key from the snature
hash := hs.Hash(tx)
pub, err := crypto.Ecrecover(hash[:], sig)
if err != nil {
return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
return nil, errors.New("invalid public key")
}
return pub, nil
}
type FrontierSigner struct{}
// WithSignature returns a new transaction with the given snature.
// This snature needs to be formatted as described in the yellow paper (v+27).
func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
return cpy, nil
}
func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := fs.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return fs.WithSignature(tx, sig)
}
// Hash returns the hash to be sned by the sender.
// It does not uniquely identify the transaction.
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Recipient,
tx.data.Amount,
tx.data.Payload,
})
}
func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
if tx.data.V.BitLen() > 8 {
return nil, ErrInvalidSig
}
V := byte(tx.data.V.Uint64())
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
return nil, ErrInvalidSig
}
// encode the snature in uncompressed format
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V - 27
// recover the public key from the snature
hash := fs.Hash(tx)
pub, err := crypto.Ecrecover(hash[:], sig)
if err != nil {
return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
return nil, errors.New("invalid public key")
}
return pub, nil
}
// normaliseV returns the Ethereum version of the V parameter
func normaliseV(s Signer, v *big.Int) byte {
if s, ok := s.(EIP155Signer); ok {
stdV := v.BitLen() <= 8 && (v.Uint64() == 27 || v.Uint64() == 28)
if s.chainId.BitLen() > 0 && !stdV {
nv := byte((new(big.Int).Sub(v, s.chainIdMul).Uint64()) - 35 + 27)
return nv
}
}
return byte(v.Uint64())
}
// deriveChainId derives the chain id from the given v parameter
func deriveChainId(v *big.Int) *big.Int {
if v.BitLen() <= 64 {
v := v.Uint64()
if v == 27 || v == 28 {
return new(big.Int)
}
return new(big.Int).SetUint64((v - 35) / 2)
}
v = new(big.Int).Sub(v, big.NewInt(35))
return v.Div(v, big.NewInt(2))
}

View File

@ -0,0 +1,116 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
)
func TestEIP155Signing(t *testing.T) {
key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey)
signer := NewEIP155Signer(big.NewInt(18))
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
if err != nil {
t.Fatal(err)
}
from, err := Sender(signer, tx)
if err != nil {
t.Fatal(err)
}
if from != addr {
t.Errorf("exected from and address to be equal. Got %x want %x", from, addr)
}
}
func TestEIP155ChainId(t *testing.T) {
key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey)
signer := NewEIP155Signer(big.NewInt(18))
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
if err != nil {
t.Fatal(err)
}
if !tx.Protected() {
t.Fatal("expected tx to be protected")
}
if tx.ChainId().Cmp(signer.chainId) != 0 {
t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId())
}
tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil)
tx, err = tx.SignECDSA(HomesteadSigner{}, key)
if err != nil {
t.Fatal(err)
}
if tx.Protected() {
t.Error("didn't expect tx to be protected")
}
if tx.ChainId().BitLen() > 0 {
t.Error("expected chain id to be 0 got", tx.ChainId())
}
}
func TestEIP155SigningVitalik(t *testing.T) {
// Test vectors come from http://vitalik.ca/files/eip155_testvec.txt
for i, test := range []struct {
txRlp, addr string
}{
{"f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"},
{"f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"},
{"f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"},
{"f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"},
{"f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"},
{"f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"},
{"f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"},
{"f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"},
{"f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"},
{"f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"},
} {
signer := NewEIP155Signer(big.NewInt(1))
var tx *Transaction
err := rlp.DecodeBytes(common.Hex2Bytes(test.txRlp), &tx)
if err != nil {
t.Errorf("%d: %v", i, err)
continue
}
from, err := Sender(signer, tx)
if err != nil {
t.Errorf("%d: %v", i, err)
continue
}
addr := common.HexToAddress(test.addr)
if from != addr {
t.Errorf("%d: expected %x got %x", i, addr, from)
}
}
}

View File

@ -46,15 +46,16 @@ var (
big.NewInt(1), big.NewInt(1),
common.FromHex("5544"), common.FromHex("5544"),
).WithSignature( ).WithSignature(
HomesteadSigner{},
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"), common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
) )
) )
func TestTransactionSigHash(t *testing.T) { func TestTransactionSigHash(t *testing.T) {
if emptyTx.SigHash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") { if emptyTx.SigHash(HomesteadSigner{}) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash()) t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash())
} }
if rightvrsTx.SigHash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") { if rightvrsTx.SigHash(HomesteadSigner{}) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash()) t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash())
} }
} }
@ -72,7 +73,9 @@ func TestTransactionEncode(t *testing.T) {
func decodeTx(data []byte) (*Transaction, error) { func decodeTx(data []byte) (*Transaction, error) {
var tx Transaction var tx Transaction
return &tx, rlp.Decode(bytes.NewReader(data), &tx) t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx)
return t, err
} }
func defaultTestKey() (*ecdsa.PrivateKey, common.Address) { func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
@ -88,7 +91,8 @@ func TestRecipientEmpty(t *testing.T) {
t.Error(err) t.Error(err)
t.FailNow() t.FailNow()
} }
from, err := tx.From()
from, err := Sender(HomesteadSigner{}, tx)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
t.FailNow() t.FailNow()
@ -107,7 +111,7 @@ func TestRecipientNormal(t *testing.T) {
t.FailNow() t.FailNow()
} }
from, err := tx.From() from, err := Sender(HomesteadSigner{}, tx)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
t.FailNow() t.FailNow()
@ -127,12 +131,14 @@ func TestTransactionPriceNonceSort(t *testing.T) {
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
keys[i], _ = crypto.GenerateKey() keys[i], _ = crypto.GenerateKey()
} }
signer := HomesteadSigner{}
// Generate a batch of transactions with overlapping values, but shifted nonces // Generate a batch of transactions with overlapping values, but shifted nonces
groups := map[common.Address]Transactions{} groups := map[common.Address]Transactions{}
for start, key := range keys { for start, key := range keys {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
for i := 0; i < 25; i++ { for i := 0; i < 25; i++ {
tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(key) tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(signer, key)
groups[addr] = append(groups[addr], tx) groups[addr] = append(groups[addr], tx)
} }
} }
@ -148,11 +154,11 @@ func TestTransactionPriceNonceSort(t *testing.T) {
break break
} }
for i, txi := range txs { for i, txi := range txs {
fromi, _ := txi.From() fromi, _ := Sender(signer, txi)
// Make sure the nonce order is valid // Make sure the nonce order is valid
for j, txj := range txs[i+1:] { for j, txj := range txs[i+1:] {
fromj, _ := txj.From() fromj, _ := Sender(signer, txj)
if fromi == fromj && txi.Nonce() > txj.Nonce() { if fromi == fromj && txi.Nonce() > txj.Nonce() {
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
@ -161,20 +167,20 @@ func TestTransactionPriceNonceSort(t *testing.T) {
// Find the previous and next nonce of this account // Find the previous and next nonce of this account
prev, next := i-1, i+1 prev, next := i-1, i+1
for j := i - 1; j >= 0; j-- { for j := i - 1; j >= 0; j-- {
if fromj, _ := txs[j].From(); fromi == fromj { if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
prev = j prev = j
break break
} }
} }
for j := i + 1; j < len(txs); j++ { for j := i + 1; j < len(txs); j++ {
if fromj, _ := txs[j].From(); fromi == fromj { if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
next = j next = j
break break
} }
} }
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise // Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
for j := prev + 1; j < next; j++ { for j := prev + 1; j < next; j++ {
fromj, _ := txs[j].From() fromj, _ := Sender(signer, txs[j])
if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 { if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice()) t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
} }

View File

@ -23,20 +23,11 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
// RuleSet is an interface that defines the current rule set during the
// execution of the EVM instructions (e.g. whether it's homestead)
type RuleSet interface {
IsHomestead(*big.Int) bool
// GasTable returns the gas prices for this phase, which is based on
// block number passed in.
GasTable(*big.Int) params.GasTable
}
// Environment is an EVM requirement and helper which allows access to outside // Environment is an EVM requirement and helper which allows access to outside
// information such as states. // information such as states.
type Environment interface { type Environment interface {
// The current ruleset // The current ruleset
RuleSet() RuleSet ChainConfig() *params.ChainConfig
// The state database // The state database
Db() Database Db() Database
// Creates a restorable snapshot // Creates a restorable snapshot
@ -115,6 +106,9 @@ type Database interface {
// Exist reports whether the given account exists in state. // Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts. // Notably this should also return true for suicided accounts.
Exist(common.Address) bool Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address) bool
} }
// Account represents a contract or basic ethereum account. // Account represents a contract or basic ethereum account.

View File

@ -515,7 +515,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
input = memory.Get(offset.Int64(), size.Int64()) input = memory.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(contract.Gas) gas = new(big.Int).Set(contract.Gas)
) )
if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil { if env.ChainConfig().IsEIP150(env.BlockNumber()) {
gas.Div(gas, n64) gas.Div(gas, n64)
gas = gas.Sub(contract.Gas, gas) gas = gas.Sub(contract.Gas, gas)
} }
@ -526,7 +526,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
// homestead we must check for CodeStoreOutOfGasError (homestead only // homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must // rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful. // ignore this error and pretend the operation was successful.
if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { if env.ChainConfig().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
stack.push(new(big.Int)) stack.push(new(big.Int))
} else if suberr != nil && suberr != CodeStoreOutOfGasError { } else if suberr != nil && suberr != CodeStoreOutOfGasError {
stack.push(new(big.Int)) stack.push(new(big.Int))

View File

@ -319,7 +319,7 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *Stack, env
}() }()
} }
homestead := env.RuleSet().IsHomestead(env.BlockNumber()) homestead := env.ChainConfig().IsHomestead(env.BlockNumber())
for pc < uint64(len(program.instructions)) { for pc < uint64(len(program.instructions)) {
instrCount++ instrCount++

View File

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
) )
const maxRun = 1000 const maxRun = 1000
@ -172,7 +173,9 @@ func NewEnv(config *Config) *Env {
return env return env
} }
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} } func (self *Env) ChainConfig() *params.ChainConfig {
return params.TestChainConfig
}
func (self *Env) Vm() Vm { return self.evm } func (self *Env) Vm() Vm { return self.evm }
func (self *Env) Origin() common.Address { return common.Address{} } func (self *Env) Origin() common.Address { return common.Address{} }
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }

View File

@ -16,7 +16,11 @@
package vm package vm
import "math/big" import (
"math/big"
"github.com/ethereum/go-ethereum/params"
)
type jumpPtr struct { type jumpPtr struct {
fn instrFn fn instrFn
@ -25,7 +29,7 @@ type jumpPtr struct {
type vmJumpTable [256]jumpPtr type vmJumpTable [256]jumpPtr
func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable { func newJumpTable(ruleset *params.ChainConfig, blockNumber *big.Int) vmJumpTable {
var jumpTable vmJumpTable var jumpTable vmJumpTable
// when initialising a new VM execution we must first check the homestead // when initialising a new VM execution we must first check the homestead

View File

@ -19,16 +19,18 @@ package vm
import ( import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/params"
) )
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(0)) jumpTable := newJumpTable(&params.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(0))
if jumpTable[DELEGATECALL].valid { if jumpTable[DELEGATECALL].valid {
t.Error("Expected DELEGATECALL not to be present") t.Error("Expected DELEGATECALL not to be present")
} }
for _, n := range []int64{1, 2, 100} { for _, n := range []int64{1, 2, 100} {
jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(n)) jumpTable := newJumpTable(&params.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(n))
if !jumpTable[DELEGATECALL].valid { if !jumpTable[DELEGATECALL].valid {
t.Error("Expected DELEGATECALL to be present for block", n) t.Error("Expected DELEGATECALL to be present for block", n)
} }

View File

@ -23,13 +23,14 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
) )
// Env is a basic runtime environment required for running the EVM. // Env is a basic runtime environment required for running the EVM.
type Env struct { type Env struct {
ruleSet vm.RuleSet chainConfig *params.ChainConfig
depth int depth int
state *state.StateDB state *state.StateDB
origin common.Address origin common.Address
coinbase common.Address coinbase common.Address
@ -47,14 +48,14 @@ type Env struct {
// NewEnv returns a new vm.Environment // NewEnv returns a new vm.Environment
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
env := &Env{ env := &Env{
ruleSet: cfg.RuleSet, chainConfig: cfg.ChainConfig,
state: state, state: state,
origin: cfg.Origin, origin: cfg.Origin,
coinbase: cfg.Coinbase, coinbase: cfg.Coinbase,
number: cfg.BlockNumber, number: cfg.BlockNumber,
time: cfg.Time, time: cfg.Time,
difficulty: cfg.Difficulty, difficulty: cfg.Difficulty,
gasLimit: cfg.GasLimit, gasLimit: cfg.GasLimit,
} }
env.evm = vm.New(env, vm.Config{ env.evm = vm.New(env, vm.Config{
Debug: cfg.Debug, Debug: cfg.Debug,
@ -65,16 +66,16 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
return env return env
} }
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet } func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig }
func (self *Env) Vm() vm.Vm { return self.evm } func (self *Env) Vm() vm.Vm { return self.evm }
func (self *Env) Origin() common.Address { return self.origin } func (self *Env) Origin() common.Address { return self.origin }
func (self *Env) BlockNumber() *big.Int { return self.number } func (self *Env) BlockNumber() *big.Int { return self.number }
func (self *Env) Coinbase() common.Address { return self.coinbase } func (self *Env) Coinbase() common.Address { return self.coinbase }
func (self *Env) Time() *big.Int { return self.time } func (self *Env) Time() *big.Int { return self.time }
func (self *Env) Difficulty() *big.Int { return self.difficulty } func (self *Env) Difficulty() *big.Int { return self.difficulty }
func (self *Env) Db() vm.Database { return self.state } func (self *Env) Db() vm.Database { return self.state }
func (self *Env) GasLimit() *big.Int { return self.gasLimit } func (self *Env) GasLimit() *big.Int { return self.gasLimit }
func (self *Env) VmType() vm.Type { return vm.StdVmTy } func (self *Env) VmType() vm.Type { return vm.StdVmTy }
func (self *Env) GetHash(n uint64) common.Hash { func (self *Env) GetHash(n uint64) common.Hash {
return self.getHashFn(n) return self.getHashFn(n)
} }

View File

@ -22,7 +22,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -39,7 +38,7 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
// Config is a basic type specifying certain configuration flags for running // Config is a basic type specifying certain configuration flags for running
// the EVM. // the EVM.
type Config struct { type Config struct {
RuleSet vm.RuleSet ChainConfig *params.ChainConfig
Difficulty *big.Int Difficulty *big.Int
Origin common.Address Origin common.Address
Coinbase common.Address Coinbase common.Address
@ -57,8 +56,16 @@ type Config struct {
// sets defaults on the config // sets defaults on the config
func setDefaults(cfg *Config) { func setDefaults(cfg *Config) {
if cfg.RuleSet == nil { if cfg.ChainConfig == nil {
cfg.RuleSet = ruleSet{} cfg.ChainConfig = &params.ChainConfig{
ChainId: big.NewInt(1),
HomesteadBlock: new(big.Int),
DAOForkBlock: new(big.Int),
DAOForkSupport: false,
EIP150Block: new(big.Int),
EIP155Block: new(big.Int),
EIP158Block: new(big.Int),
}
} }
if cfg.Difficulty == nil { if cfg.Difficulty == nil {

View File

@ -51,9 +51,9 @@ type EVM struct {
func New(env Environment, cfg Config) *EVM { func New(env Environment, cfg Config) *EVM {
return &EVM{ return &EVM{
env: env, env: env,
jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()), jumpTable: newJumpTable(env.ChainConfig(), env.BlockNumber()),
cfg: cfg, cfg: cfg,
gasTable: env.RuleSet().GasTable(env.BlockNumber()), gasTable: env.ChainConfig().GasTable(env.BlockNumber()),
} }
} }
@ -172,6 +172,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Get the memory location of pc // Get the memory location of pc
op = contract.GetOp(pc) op = contract.GetOp(pc)
//fmt.Printf("OP %d %v\n", op, op)
// calculate the new memory size and gas price for the current executing opcode // calculate the new memory size and gas price for the current executing opcode
newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack) newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
if err != nil { if err != nil {
@ -254,10 +255,20 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
// stack Check, memory resize & gas phase // stack Check, memory resize & gas phase
switch op { switch op {
case SUICIDE: case SUICIDE:
// if suicide is not nil: homestead gas fork // EIP150 homestead gas reprice fork:
if gasTable.CreateBySuicide != nil { if gasTable.CreateBySuicide != nil {
gas.Set(gasTable.Suicide) gas.Set(gasTable.Suicide)
if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) { var (
address = common.BigToAddress(stack.data[len(stack.data)-1])
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber())
)
if eip158 {
// if empty and transfers value
if env.Db().Empty(address) && statedb.GetBalance(contract.Address()).BitLen() > 0 {
gas.Add(gas, gasTable.CreateBySuicide)
}
} else if !env.Db().Exist(address) {
gas.Add(gas, gasTable.CreateBySuicide) gas.Add(gas, gasTable.CreateBySuicide)
} }
} }
@ -302,7 +313,8 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
quadMemGas(mem, newMemSize, gas) quadMemGas(mem, newMemSize, gas)
case EXP: case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
gas.Add(gas, new(big.Int).Mul(big.NewInt(expByteLen), gasTable.ExpByte))
case SSTORE: case SSTORE:
err := stack.require(2) err := stack.require(2)
if err != nil { if err != nil {
@ -378,12 +390,21 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
case CALL, CALLCODE: case CALL, CALLCODE:
gas.Set(gasTable.Calls) gas.Set(gasTable.Calls)
transfersValue := stack.data[len(stack.data)-3].BitLen() > 0
if op == CALL { if op == CALL {
if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) { var (
address = common.BigToAddress(stack.data[len(stack.data)-2])
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber())
)
if eip158 {
if env.Db().Empty(address) && transfersValue {
gas.Add(gas, params.CallNewAccountGas)
}
} else if !env.Db().Exist(address) {
gas.Add(gas, params.CallNewAccountGas) gas.Add(gas, params.CallNewAccountGas)
} }
} }
if len(stack.data[stack.len()-3].Bytes()) > 0 { if transfersValue {
gas.Add(gas, params.CallValueTransferGas) gas.Add(gas, params.CallValueTransferGas)
} }
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])

View File

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
) )
// GetHashFn returns a function for which the VM env can query block hashes through // GetHashFn returns a function for which the VM env can query block hashes through
@ -41,18 +42,18 @@ func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash {
} }
type VMEnv struct { type VMEnv struct {
chainConfig *ChainConfig // Chain configuration chainConfig *params.ChainConfig // Chain configuration
state *state.StateDB // State to use for executing state *state.StateDB // State to use for executing
evm *vm.EVM // The Ethereum Virtual Machine evm *vm.EVM // The Ethereum Virtual Machine
depth int // Current execution depth depth int // Current execution depth
msg Message // Message appliod msg Message // Message appliod
header *types.Header // Header information header *types.Header // Header information
chain *BlockChain // Blockchain handle chain *BlockChain // Blockchain handle
getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes
} }
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv { func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
env := &VMEnv{ env := &VMEnv{
chainConfig: chainConfig, chainConfig: chainConfig,
chain: chain, chain: chain,
@ -66,18 +67,18 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
return env return env
} }
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig } func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
func (self *VMEnv) Vm() vm.Vm { return self.evm } func (self *VMEnv) Vm() vm.Vm { return self.evm }
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } func (self *VMEnv) Origin() common.Address { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
func (self *VMEnv) Time() *big.Int { return self.header.Time } func (self *VMEnv) Time() *big.Int { return self.header.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) Db() vm.Database { return self.state } func (self *VMEnv) Db() vm.Database { return self.state }
func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) GetHash(n uint64) common.Hash { func (self *VMEnv) GetHash(n uint64) common.Hash {
return self.getHashFn(n) return self.getHashFn(n)
} }

View File

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -303,13 +304,13 @@ func (api *PublicDebugAPI) DumpBlock(number uint64) (state.Dump, error) {
// PrivateDebugAPI is the collection of Etheruem full node APIs exposed over // PrivateDebugAPI is the collection of Etheruem full node APIs exposed over
// the private debugging endpoint. // the private debugging endpoint.
type PrivateDebugAPI struct { type PrivateDebugAPI struct {
config *core.ChainConfig config *params.ChainConfig
eth *Ethereum eth *Ethereum
} }
// NewPrivateDebugAPI creates a new API definition for the full node-related // NewPrivateDebugAPI creates a new API definition for the full node-related
// private debug methods of the Ethereum service. // private debug methods of the Ethereum service.
func NewPrivateDebugAPI(config *core.ChainConfig, eth *Ethereum) *PrivateDebugAPI { func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebugAPI {
return &PrivateDebugAPI{config: config, eth: eth} return &PrivateDebugAPI{config: config, eth: eth}
} }
@ -505,21 +506,15 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
if err != nil { if err != nil {
return nil, err return nil, err
} }
signer := types.MakeSigner(api.config, block.Number())
// Mutate the state and trace the selected transaction // Mutate the state and trace the selected transaction
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message // Assemble the transaction call message
from, err := tx.FromFrontier() msg, err := tx.AsMessage(signer)
if err != nil { if err != nil {
return nil, fmt.Errorf("sender retrieval failed: %v", err) return nil, fmt.Errorf("sender retrieval failed: %v", err)
} }
msg := callmsg{
addr: from,
to: tx.To(),
gas: tx.Gas(),
gasPrice: tx.GasPrice(),
value: tx.Value(),
data: tx.Data(),
}
// Mutate the state if we haven't reached the tracing transaction yet // Mutate the state if we haven't reached the tracing transaction yet
if uint64(idx) < txIndex { if uint64(idx) < txIndex {
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{}) vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/params"
rpc "github.com/ethereum/go-ethereum/rpc" rpc "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -40,6 +41,14 @@ type EthApiBackend struct {
gpo *gasprice.GasPriceOracle gpo *gasprice.GasPriceOracle
} }
func (b *EthApiBackend) ChainConfig() *params.ChainConfig {
return b.eth.chainConfig
}
func (b *EthApiBackend) CurrentBlock() *types.Block {
return b.eth.blockchain.CurrentBlock()
}
func (b *EthApiBackend) SetHead(number uint64) { func (b *EthApiBackend) SetHead(number uint64) {
b.eth.blockchain.SetHead(number) b.eth.blockchain.SetHead(number)
} }
@ -99,11 +108,10 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
statedb := state.(EthApiState).state statedb := state.(EthApiState).state
addr, _ := msg.From() from := statedb.GetOrNewStateObject(msg.From())
from := statedb.GetOrNewStateObject(addr)
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
vmError := func() error { return nil } vmError := func() error { return nil }
return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil
} }
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {

View File

@ -35,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/common/registrar/ethreg" "github.com/ethereum/go-ethereum/common/registrar/ethreg"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/gasprice"
@ -47,6 +46,7 @@ import (
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -64,7 +64,7 @@ var (
) )
type Config struct { type Config struct {
ChainConfig *core.ChainConfig // chain configuration ChainConfig *params.ChainConfig // chain configuration
NetworkId int // Network ID to use for selecting peers to connect to NetworkId int // Network ID to use for selecting peers to connect to
Genesis string // Genesis JSON to seed the chain database with Genesis string // Genesis JSON to seed the chain database with
@ -112,7 +112,7 @@ type LesServer interface {
// Ethereum implements the Ethereum full node service. // Ethereum implements the Ethereum full node service.
type Ethereum struct { type Ethereum struct {
chainConfig *core.ChainConfig chainConfig *params.ChainConfig
// Channel for shutting down the service // Channel for shutting down the service
shutdownChan chan bool // Channel for shutting down the ethereum shutdownChan chan bool // Channel for shutting down the ethereum
stopDbUpgrade func() // stop chain db sequential key upgrade stopDbUpgrade func() // stop chain db sequential key upgrade
@ -217,10 +217,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig) core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
eth.chainConfig = config.ChainConfig eth.chainConfig = config.ChainConfig
eth.chainConfig.VmConfig = vm.Config{
EnableJit: config.EnableJit,
ForceJit: config.ForceJit,
}
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux()) eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
if err != nil { if err != nil {

View File

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
) )
func TestMipmapUpgrade(t *testing.T) { func TestMipmapUpgrade(t *testing.T) {
@ -32,7 +33,7 @@ func TestMipmapUpgrade(t *testing.T) {
addr := common.BytesToAddress([]byte("jeff")) addr := common.BytesToAddress([]byte("jeff"))
genesis := core.WriteGenesisBlockForTesting(db) genesis := core.WriteGenesisBlockForTesting(db)
chain, receipts := core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -109,7 +109,7 @@ func newTester() *downloadTester {
// reassembly. // reassembly.
func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) { func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) {
// Generate the block chain // Generate the block chain
blocks, receipts := core.GenerateChain(nil, parent, dl.peerDb, n, func(i int, block *core.BlockGen) { blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, dl.peerDb, n, func(i int, block *core.BlockGen) {
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// If a heavy chain is requested, delay blocks to raise difficulty // If a heavy chain is requested, delay blocks to raise difficulty
@ -118,7 +118,8 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren
} }
// If the block number is multiple of 3, send a bonus transaction to the miner // If the block number is multiple of 3, send a bonus transaction to the miner
if parent == dl.genesis && i%3 == 0 { if parent == dl.genesis && i%3 == 0 {
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey) signer := types.MakeSigner(params.TestChainConfig, block.Number())
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -45,12 +45,13 @@ var (
// contains a transaction and every 5th an uncle to allow testing correct block // contains a transaction and every 5th an uncle to allow testing correct block
// reassembly. // reassembly.
func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
blocks, _ := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) { blocks, _ := core.GenerateChain(params.TestChainConfig, parent, testdb, n, func(i int, block *core.BlockGen) {
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// If the block number is multiple of 3, send a bonus transaction to the miner // If the block number is multiple of 3, send a bonus transaction to the miner
if parent == genesis && i%3 == 0 { if parent == genesis && i%3 == 0 {
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey) signer := types.MakeSigner(params.TestChainConfig, block.Number())
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -81,7 +82,7 @@ func TestBlockSubscription(t *testing.T) {
var ( var (
genesis = core.WriteGenesisBlockForTesting(db) genesis = core.WriteGenesisBlockForTesting(db)
chain, _ = core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {}) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
chainEvents = []core.ChainEvent{} chainEvents = []core.ChainEvent{}
) )

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
) )
func makeReceipt(addr common.Address) *types.Receipt { func makeReceipt(addr common.Address) *types.Receipt {
@ -60,7 +61,7 @@ func BenchmarkMipmaps(b *testing.B) {
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)}) genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 2403: case 2403:
@ -137,7 +138,7 @@ func TestFilters(t *testing.T) {
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)}) genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -67,7 +68,7 @@ type ProtocolManager struct {
txpool txPool txpool txPool
blockchain *core.BlockChain blockchain *core.BlockChain
chaindb ethdb.Database chaindb ethdb.Database
chainconfig *core.ChainConfig chainconfig *params.ChainConfig
maxPeers int maxPeers int
downloader *downloader.Downloader downloader *downloader.Downloader
@ -95,7 +96,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network. // with the ethereum network.
func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) { func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
// Create the protocol manager with the base fields // Create the protocol manager with the base fields
manager := &ProtocolManager{ manager := &ProtocolManager{
networkId: networkId, networkId: networkId,

View File

@ -305,18 +305,19 @@ func testGetNodeData(t *testing.T, protocol int) {
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
signer := types.HomesteadSigner{}
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
generator := func(i int, block *core.BlockGen) { generator := func(i int, block *core.BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
case 2: case 2:
@ -396,18 +397,19 @@ func testGetReceipt(t *testing.T, protocol int) {
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
signer := types.HomesteadSigner{}
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
generator := func(i int, block *core.BlockGen) { generator := func(i int, block *core.BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
case 2: case 2:
@ -466,7 +468,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
pow = new(core.FakePow) pow = new(core.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db) genesis = core.WriteGenesisBlockForTesting(db)
config = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
blockchain, _ = core.NewBlockChain(db, config, pow, evmux) blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
) )
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db) pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
@ -491,7 +493,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
} }
// Create a block to reply to the challenge if no timeout is simualted // Create a block to reply to the challenge if no timeout is simualted
if !timeout { if !timeout {
blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) { blocks, _ := core.GenerateChain(&params.ChainConfig{}, genesis, db, 1, func(i int, block *core.BlockGen) {
if remoteForked { if remoteForked {
block.SetExtra(params.DAOForkBlockExtra) block.SetExtra(params.DAOForkBlockExtra)
} }

View File

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params"
) )
var ( var (
@ -54,10 +55,10 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
pow = new(core.FakePow) pow = new(core.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, testBank) genesis = core.WriteGenesisBlockForTesting(db, testBank)
chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux) blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
) )
chain, _ := core.GenerateChain(nil, genesis, db, blocks, generator) chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
panic(err) panic(err)
} }
@ -109,7 +110,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
batches := make(map[common.Address]types.Transactions) batches := make(map[common.Address]types.Transactions)
for _, tx := range p.pool { for _, tx := range p.pool {
from, _ := tx.From() from, _ := types.Sender(types.HomesteadSigner{}, tx)
batches[from] = append(batches[from], tx) batches[from] = append(batches[from], tx)
} }
for _, batch := range batches { for _, batch := range batches {
@ -121,7 +122,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
// newTestTransaction create a new dummy transaction. // newTestTransaction create a new dummy transaction.
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
tx, _ = tx.SignECDSA(from) tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
return tx return tx
} }

View File

@ -147,7 +147,7 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*typ
var tx *types.Transaction var tx *types.Transaction
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash) err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
if err == nil { if err == nil {
if _, r, _ := tx.SignatureValues(); r == nil { if _, r, _ := tx.RawSignatureValues(); r == nil {
return nil, fmt.Errorf("server returned transaction without signature") return nil, fmt.Errorf("server returned transaction without signature")
} }
} }
@ -166,7 +166,11 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
var tx *types.Transaction var tx *types.Transaction
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index) err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index)
if err == nil { if err == nil {
if _, r, _ := tx.SignatureValues(); r == nil { var signer types.Signer = types.HomesteadSigner{}
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
if _, r, _ := types.SignatureValues(signer, tx); r == nil {
return nil, fmt.Errorf("server returned transaction without signature") return nil, fmt.Errorf("server returned transaction without signature")
} }
} }

View File

@ -279,7 +279,8 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
} }
signature, err := s.am.SignWithPassphrase(args.From, passwd, tx.SigHash().Bytes()) signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes())
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -537,22 +538,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
} }
// Assemble the CALL invocation // Assemble the CALL invocation
msg := callmsg{ gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt()
addr: addr, if gas.Cmp(common.Big0) == 0 {
to: args.To, gas = big.NewInt(50000000)
gas: args.Gas.BigInt(),
gasPrice: args.GasPrice.BigInt(),
value: args.Value.BigInt(),
data: common.FromHex(args.Data),
} }
if gasPrice.Cmp(common.Big0) == 0 {
if msg.gas.Cmp(common.Big0) == 0 { gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
msg.gas = big.NewInt(50000000)
}
if msg.gasPrice.Cmp(common.Big0) == 0 {
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
} }
msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data))
// Execute the call and return // Execute the call and return
vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header) vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
@ -714,8 +707,12 @@ type RPCTransaction struct {
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
from, _ := tx.FromFrontier() var signer types.Signer = types.FrontierSigner{}
v, r, s := tx.SignatureValues() if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
v, r, s := types.SignatureValues(signer, tx)
return &RPCTransaction{ return &RPCTransaction{
From: from, From: from,
Gas: rpc.NewHexNumber(tx.Gas()), Gas: rpc.NewHexNumber(tx.Gas()),
@ -735,11 +732,12 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) {
if txIndex >= 0 && txIndex < len(b.Transactions()) { if txIndex >= 0 && txIndex < len(b.Transactions()) {
tx := b.Transactions()[txIndex] tx := b.Transactions()[txIndex]
from, err := tx.FromFrontier() var signer types.Signer = types.FrontierSigner{}
if err != nil { if tx.Protected() {
return nil, err signer = types.NewEIP155Signer(tx.ChainId())
} }
v, r, s := tx.SignatureValues() from, _ := types.Sender(signer, tx)
v, r, s := tx.RawSignatureValues()
return &RPCTransaction{ return &RPCTransaction{
BlockHash: b.Hash(), BlockHash: b.Hash(),
BlockNumber: rpc.NewHexNumber(b.Number()), BlockNumber: rpc.NewHexNumber(b.Number()),
@ -958,11 +956,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
return nil, nil return nil, nil
} }
from, err := tx.FromFrontier() var signer types.Signer = types.FrontierSigner{}
if err != nil { if tx.Protected() {
glog.V(logger.Debug).Infof("%v\n", err) signer = types.NewEIP155Signer(tx.ChainId())
return nil, nil
} }
from, _ := types.Sender(signer, tx)
fields := map[string]interface{}{ fields := map[string]interface{}{
"root": rpc.HexBytes(receipt.PostState), "root": rpc.HexBytes(receipt.PostState),
@ -990,11 +988,13 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
// sign is a helper function that signs a transaction with the private key of the given address. // sign is a helper function that signs a transaction with the private key of the given address.
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
signature, err := s.b.AccountManager().SignEthereum(addr, tx.SigHash().Bytes()) signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return tx.WithSignature(signature) return tx.WithSignature(signer, signature)
} }
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool. // SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
@ -1028,7 +1028,9 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA
// submitTransaction is a helper function that submits tx to txPool and creates a log entry. // submitTransaction is a helper function that submits tx to txPool and creates a log entry.
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) { func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) {
signedTx, err := tx.WithSignature(signature) signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
signedTx, err := tx.WithSignature(signer, signature)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -1038,7 +1040,7 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si
} }
if signedTx.To() == nil { if signedTx.To() == nil {
from, _ := signedTx.From() from, _ := types.Sender(signer, signedTx)
addr := crypto.CreateAddress(from, signedTx.Nonce()) addr := crypto.CreateAddress(from, signedTx.Nonce())
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex()) glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
} else { } else {
@ -1072,7 +1074,8 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
} }
signature, err := s.b.AccountManager().SignEthereum(args.From, tx.SigHash().Bytes()) signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes())
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -1092,8 +1095,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
return "", err return "", err
} }
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
if tx.To() == nil { if tx.To() == nil {
from, err := tx.FromFrontier() from, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -1202,7 +1206,12 @@ type SignTransactionResult struct {
} }
func newTx(t *types.Transaction) *Tx { func newTx(t *types.Transaction) *Tx {
from, _ := t.FromFrontier() var signer types.Signer = types.HomesteadSigner{}
if t.Protected() {
signer = types.NewEIP155Signer(t.ChainId())
}
from, _ := types.Sender(signer, t)
return &Tx{ return &Tx{
tx: t, tx: t,
To: t.To(), To: t.To(),
@ -1268,7 +1277,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
pending := s.b.GetPoolTransactions() pending := s.b.GetPoolTransactions()
transactions := make([]*RPCTransaction, 0, len(pending)) transactions := make([]*RPCTransaction, 0, len(pending))
for _, tx := range pending { for _, tx := range pending {
from, _ := tx.FromFrontier() var signer types.Signer = types.HomesteadSigner{}
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
if s.b.AccountManager().HasAddress(from) { if s.b.AccountManager().HasAddress(from) {
transactions = append(transactions, newRPCPendingTransaction(tx)) transactions = append(transactions, newRPCPendingTransaction(tx))
} }
@ -1281,7 +1294,12 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {
pending := s.b.GetPoolTransactions() pending := s.b.GetPoolTransactions()
for _, p := range pending { for _, p := range pending {
if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() { var signer types.Signer = types.HomesteadSigner{}
if p.Protected() {
signer = types.NewEIP155Signer(p.ChainId())
}
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) {
if gasPrice == nil { if gasPrice == nil {
gasPrice = rpc.NewHexNumber(tx.tx.GasPrice()) gasPrice = rpc.NewHexNumber(tx.tx.GasPrice())
} }

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -59,6 +60,9 @@ type Backend interface {
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Stats() (pending int, queued int) Stats() (pending int, queued int)
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
} }
type State interface { type State interface {

View File

@ -29,11 +29,6 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
type ruleSet struct{}
func (self *ruleSet) IsHomestead(*big.Int) bool { return true }
func (*ruleSet) GasTable(*big.Int) params.GasTable { return params.GasTableHomesteadGasRepriceFork }
type Env struct { type Env struct {
gasLimit *big.Int gasLimit *big.Int
depth int depth int
@ -46,7 +41,9 @@ func NewEnv(config *vm.Config) *Env {
return env return env
} }
func (self *Env) RuleSet() vm.RuleSet { return &ruleSet{} } func (self *Env) ChainConfig() *params.ChainConfig {
return params.TestChainConfig
}
func (self *Env) Vm() vm.Vm { return self.evm } func (self *Env) Vm() vm.Vm { return self.evm }
func (self *Env) Origin() common.Address { return common.Address{} } func (self *Env) Origin() common.Address { return common.Address{} }
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
rpc "github.com/ethereum/go-ethereum/rpc" rpc "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -39,6 +40,14 @@ type LesApiBackend struct {
gpo *gasprice.LightPriceOracle gpo *gasprice.LightPriceOracle
} }
func (b *LesApiBackend) ChainConfig() *params.ChainConfig {
return b.eth.chainConfig
}
func (b *LesApiBackend) CurrentBlock() *types.Block {
return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader())
}
func (b *LesApiBackend) SetHead(number uint64) { func (b *LesApiBackend) SetHead(number uint64) {
b.eth.blockchain.SetHead(number) b.eth.blockchain.SetHead(number)
} }
@ -81,13 +90,13 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
stateDb := state.(*light.LightState).Copy() stateDb := state.(*light.LightState).Copy()
addr, _ := msg.From() addr := msg.From()
from, err := stateDb.GetOrNewStateObject(ctx, addr) from, err := stateDb.GetOrNewStateObject(ctx, addr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig) env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{})
return env, env.Error, nil return env, env.Error, nil
} }

View File

@ -29,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/common/httpclient" "github.com/ethereum/go-ethereum/common/httpclient"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/filters"
@ -42,13 +41,14 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
rpc "github.com/ethereum/go-ethereum/rpc" rpc "github.com/ethereum/go-ethereum/rpc"
) )
type LightEthereum struct { type LightEthereum struct {
odr *LesOdr odr *LesOdr
relay *LesTxRelay relay *LesTxRelay
chainConfig *core.ChainConfig chainConfig *params.ChainConfig
// Channel for shutting down the service // Channel for shutting down the service
shutdownChan chan bool shutdownChan chan bool
// Handlers // Handlers
@ -107,10 +107,6 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
return nil, errors.New("missing chain config") return nil, errors.New("missing chain config")
} }
eth.chainConfig = config.ChainConfig eth.chainConfig = config.ChainConfig
eth.chainConfig.VmConfig = vm.Config{
EnableJit: config.EnableJit,
ForceJit: config.ForceJit,
}
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux) eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
if err != nil { if err != nil {
if err == core.ErrNoGenesis { if err == core.ErrNoGenesis {

View File

@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -95,7 +96,7 @@ type ProtocolManager struct {
txpool txPool txpool txPool
txrelay *LesTxRelay txrelay *LesTxRelay
networkId int networkId int
chainConfig *core.ChainConfig chainConfig *params.ChainConfig
blockchain BlockChain blockchain BlockChain
chainDb ethdb.Database chainDb ethdb.Database
odr *LesOdr odr *LesOdr
@ -129,7 +130,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network. // with the ethereum network.
func NewProtocolManager(chainConfig *core.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) { func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
// Create the protocol manager with the base fields // Create the protocol manager with the base fields
manager := &ProtocolManager{ manager := &ProtocolManager{
lightSync: lightSync, lightSync: lightSync,

View File

@ -73,20 +73,22 @@ contract test {
*/ */
func testChainGen(i int, block *core.BlockGen) { func testChainGen(i int, block *core.BlockGen) {
signer := types.HomesteadSigner{}
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
// acc1Addr creates a test contract. // acc1Addr creates a test contract.
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
nonce := block.TxNonce(acc1Addr) nonce := block.TxNonce(acc1Addr)
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
nonce++ nonce++
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(acc1Key) tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce) testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
@ -96,7 +98,7 @@ func testChainGen(i int, block *core.BlockGen) {
block.SetCoinbase(acc2Addr) block.SetCoinbase(acc2Addr)
block.SetExtra([]byte("yeehaw")) block.SetExtra([]byte("yeehaw"))
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 3: case 3:
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
@ -107,7 +109,7 @@ func testChainGen(i int, block *core.BlockGen) {
b3.Extra = []byte("foo") b3.Extra = []byte("foo")
block.AddUncle(b3) block.AddUncle(b3)
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
} }
} }
@ -131,7 +133,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
pow = new(core.FakePow) pow = new(core.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
odr *LesOdr odr *LesOdr
chain BlockChain chain BlockChain
) )
@ -141,7 +143,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux) chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
} else { } else {
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux) blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux)
gchain, _ := core.GenerateChain(nil, genesis, db, blocks, generator) gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(gchain); err != nil { if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err) panic(err)
} }
@ -214,7 +216,7 @@ func (p *testTxPool) GetTransactions() types.Transactions {
// newTestTransaction create a new dummy transaction. // newTestTransaction create a new dummy transaction.
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
tx, _ = tx.SignECDSA(from) tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
return tx return tx
} }

View File

@ -26,17 +26,19 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
type odrTestFn func(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) } func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
var block *types.Block var block *types.Block
if bc != nil { if bc != nil {
block = bc.GetBlockByHash(bhash) block = bc.GetBlockByHash(bhash)
@ -52,7 +54,7 @@ func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfi
func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) } func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) }
func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
var receipts types.Receipts var receipts types.Receipts
if bc != nil { if bc != nil {
receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash))
@ -68,7 +70,7 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainCo
func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) } func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) }
func odrAccounts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678") dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr} acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
@ -98,47 +100,13 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *core.ChainConfi
func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) } func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) }
// fullcallmsg is the message type used for call transations. type callmsg struct {
type fullcallmsg struct { types.Message
from *state.StateObject
to *common.Address
gas, gasPrice *big.Int
value *big.Int
data []byte
} }
// accessor boilerplate to implement core.Message func (callmsg) CheckNonce() bool { return false }
func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
func (m fullcallmsg) Nonce() uint64 { return 0 }
func (m fullcallmsg) CheckNonce() bool { return false }
func (m fullcallmsg) To() *common.Address { return m.to }
func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice }
func (m fullcallmsg) Gas() *big.Int { return m.gas }
func (m fullcallmsg) Value() *big.Int { return m.value }
func (m fullcallmsg) Data() []byte { return m.data }
// callmsg is the message type used for call transations. func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
type lightcallmsg struct {
from *light.StateObject
to *common.Address
gas, gasPrice *big.Int
value *big.Int
data []byte
}
// accessor boilerplate to implement core.Message
func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
func (m lightcallmsg) Nonce() uint64 { return 0 }
func (m lightcallmsg) CheckNonce() bool { return false }
func (m lightcallmsg) To() *common.Address { return m.to }
func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice }
func (m lightcallmsg) Gas() *big.Int { return m.gas }
func (m lightcallmsg) Value() *big.Int { return m.value }
func (m lightcallmsg) Data() []byte { return m.data }
func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
var res []byte var res []byte
@ -151,16 +119,8 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
from := statedb.GetOrNewStateObject(testBankAddress) from := statedb.GetOrNewStateObject(testBankAddress)
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
msg := fullcallmsg{ msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)}
from: from, vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
gas: big.NewInt(100000),
gasPrice: big.NewInt(0),
value: big.NewInt(0),
data: data,
to: &testContractAddr,
}
vmenv := core.NewEnv(statedb, config, bc, msg, header, config.VmConfig)
gp := new(core.GasPool).AddGas(common.MaxBig) gp := new(core.GasPool).AddGas(common.MaxBig)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, ret...) res = append(res, ret...)
@ -172,16 +132,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
if err == nil { if err == nil {
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
msg := lightcallmsg{ msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)}
from: from,
gas: big.NewInt(100000),
gasPrice: big.NewInt(0),
value: big.NewInt(0),
data: data,
to: &testContractAddr,
}
vmenv := light.NewEnv(ctx, state, config, lc, msg, header, config.VmConfig) vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(common.MaxBig) gp := new(core.GasPool).AddGas(common.MaxBig)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
if vmenv.Error() == nil { if vmenv.Error() == nil {

View File

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
@ -71,7 +72,7 @@ type LightChain struct {
// NewLightChain returns a fully initialised light chain using information // NewLightChain returns a fully initialised light chain using information
// available in the database. It initialises the default Ethereum header // available in the database. It initialises the default Ethereum header
// validator. // validator.
func NewLightChain(odr OdrBackend, config *core.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) { func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
bodyCache, _ := lru.New(bodyCacheLimit) bodyCache, _ := lru.New(bodyCacheLimit)
bodyRLPCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit)
blockCache, _ := lru.New(blockCacheLimit) blockCache, _ := lru.New(blockCacheLimit)

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -41,7 +42,7 @@ var (
// makeHeaderChain creates a deterministic chain of headers rooted at parent. // makeHeaderChain creates a deterministic chain of headers rooted at parent.
func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header { func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
blocks, _ := core.GenerateChain(nil, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) { blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
}) })
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
@ -51,8 +52,8 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
return headers return headers
} }
func testChainConfig() *core.ChainConfig { func testChainConfig() *params.ChainConfig {
return &core.ChainConfig{HomesteadBlock: big.NewInt(0)} return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
} }
// newCanonical creates a chain database, and injects a deterministic canonical // newCanonical creates a chain database, and injects a deterministic canonical

View File

@ -148,45 +148,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) } func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) }
// fullcallmsg is the message type used for call transations. type callmsg struct {
type fullcallmsg struct { types.Message
from *state.StateObject
to *common.Address
gas, gasPrice *big.Int
value *big.Int
data []byte
} }
// accessor boilerplate to implement core.Message func (callmsg) CheckNonce() bool { return false }
func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
func (m fullcallmsg) Nonce() uint64 { return 0 }
func (m fullcallmsg) CheckNonce() bool { return false }
func (m fullcallmsg) To() *common.Address { return m.to }
func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice }
func (m fullcallmsg) Gas() *big.Int { return m.gas }
func (m fullcallmsg) Value() *big.Int { return m.value }
func (m fullcallmsg) Data() []byte { return m.data }
// callmsg is the message type used for call transations.
type lightcallmsg struct {
from *StateObject
to *common.Address
gas, gasPrice *big.Int
value *big.Int
data []byte
}
// accessor boilerplate to implement core.Message
func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
func (m lightcallmsg) Nonce() uint64 { return 0 }
func (m lightcallmsg) CheckNonce() bool { return false }
func (m lightcallmsg) To() *common.Address { return m.to }
func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice }
func (m lightcallmsg) Gas() *big.Int { return m.gas }
func (m lightcallmsg) Value() *big.Int { return m.value }
func (m lightcallmsg) Data() []byte { return m.data }
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte { func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
@ -201,15 +167,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
from := statedb.GetOrNewStateObject(testBankAddress) from := statedb.GetOrNewStateObject(testBankAddress)
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
msg := fullcallmsg{ msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)}
from: from,
gas: big.NewInt(100000),
gasPrice: big.NewInt(0),
value: big.NewInt(0),
data: data,
to: &testContractAddr,
}
vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{}) vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(common.MaxBig) gp := new(core.GasPool).AddGas(common.MaxBig)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
@ -222,15 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
if err == nil { if err == nil {
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
msg := lightcallmsg{ msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)}
from: from,
gas: big.NewInt(100000),
gasPrice: big.NewInt(0),
value: big.NewInt(0),
data: data,
to: &testContractAddr,
}
vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{}) vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(common.MaxBig) gp := new(core.GasPool).AddGas(common.MaxBig)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
@ -244,20 +194,21 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
} }
func testChainGen(i int, block *core.BlockGen) { func testChainGen(i int, block *core.BlockGen) {
signer := types.HomesteadSigner{}
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
// acc1Addr creates a test contract. // acc1Addr creates a test contract.
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
nonce := block.TxNonce(acc1Addr) nonce := block.TxNonce(acc1Addr)
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
nonce++ nonce++
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(acc1Key) tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce) testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
@ -267,7 +218,7 @@ func testChainGen(i int, block *core.BlockGen) {
block.SetCoinbase(acc2Addr) block.SetCoinbase(acc2Addr)
block.SetExtra([]byte("yeehaw")) block.SetExtra([]byte("yeehaw"))
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 3: case 3:
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
@ -278,7 +229,7 @@ func testChainGen(i int, block *core.BlockGen) {
b3.Extra = []byte("foo") b3.Extra = []byte("foo")
block.AddUncle(b3) block.AddUncle(b3)
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
} }
} }
@ -294,7 +245,8 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
// Assemble the test environment // Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux) blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
gchain, _ := core.GenerateChain(nil, genesis, sdb, 4, testChainGen) chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, 4, testChainGen)
if _, err := blockchain.InsertChain(gchain); err != nil { if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err) panic(err)
} }

View File

@ -41,7 +41,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
st.AddBalance(addr, big.NewInt(int64(i))) st.AddBalance(addr, big.NewInt(int64(i)))
st.SetCode(addr, []byte{i, i, i}) st.SetCode(addr, []byte{i, i, i})
} }
root, _ := st.Commit() root, _ := st.Commit(false)
return root, sdb return root, sdb
} }

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -42,7 +43,8 @@ var txPermanent = uint64(500)
// always receive all locally signed transactions in the same order as they are // always receive all locally signed transactions in the same order as they are
// created. // created.
type TxPool struct { type TxPool struct {
config *core.ChainConfig config *params.ChainConfig
signer types.Signer
quit chan bool quit chan bool
eventMux *event.TypeMux eventMux *event.TypeMux
events event.Subscription events event.Subscription
@ -76,9 +78,10 @@ type TxRelayBackend interface {
} }
// NewTxPool creates a new light transaction pool // NewTxPool creates a new light transaction pool
func NewTxPool(config *core.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool { func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
pool := &TxPool{ pool := &TxPool{
config: config, config: config,
signer: types.HomesteadSigner{},
nonce: make(map[common.Address]uint64), nonce: make(map[common.Address]uint64),
pending: make(map[common.Hash]*types.Transaction), pending: make(map[common.Hash]*types.Transaction),
mined: make(map[common.Hash][]*types.Transaction), mined: make(map[common.Hash][]*types.Transaction),
@ -197,7 +200,7 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uin
if len(receipts) != len(block.Transactions()) { if len(receipts) != len(block.Transactions()) {
panic(nil) // should never happen if hashes did match panic(nil) // should never happen if hashes did match
} }
core.SetReceiptsData(block, receipts) core.SetReceiptsData(pool.config, block, receipts)
} }
//fmt.Println("WriteReceipt", receipts[i].TxHash) //fmt.Println("WriteReceipt", receipts[i].TxHash)
core.WriteReceipt(pool.chainDb, receipts[i]) core.WriteReceipt(pool.chainDb, receipts[i])
@ -308,6 +311,7 @@ func (pool *TxPool) eventLoop() {
m, r := txc.getLists() m, r := txc.getLists()
pool.relay.NewHead(pool.head, m, r) pool.relay.NewHead(pool.head, m, r)
pool.homestead = pool.config.IsHomestead(head.Number) pool.homestead = pool.config.IsHomestead(head.Number)
pool.signer = types.MakeSigner(pool.config, head.Number)
pool.mu.Unlock() pool.mu.Unlock()
} }
} }
@ -339,7 +343,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
// Validate the transaction sender and it's sig. Throw // Validate the transaction sender and it's sig. Throw
// if the from fields is invalid. // if the from fields is invalid.
if from, err = tx.From(); err != nil { if from, err = types.Sender(pool.signer, tx); err != nil {
return core.ErrInvalidSender return core.ErrInvalidSender
} }
@ -388,7 +392,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
} }
// Should supply enough intrinsic gas // Should supply enough intrinsic gas
if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), core.MessageCreatesContract(tx), pool.homestead)) < 0 { if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)) < 0 {
return core.ErrIntrinsicGas return core.ErrIntrinsicGas
} }
@ -412,7 +416,8 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
self.pending[hash] = tx self.pending[hash] = tx
nonce := tx.Nonce() + 1 nonce := tx.Nonce() + 1
addr, _ := tx.From()
addr, _ := types.Sender(self.signer, tx)
if nonce > self.nonce[addr] { if nonce > self.nonce[addr] {
self.nonce[addr] = nonce self.nonce[addr] = nonce
} }
@ -432,7 +437,7 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
} }
// we can ignore the error here because From is // we can ignore the error here because From is
// verified in ValidateTransaction. // verified in ValidateTransaction.
f, _ := tx.From() f, _ := types.Sender(self.signer, tx)
from := common.Bytes2Hex(f[:4]) from := common.Bytes2Hex(f[:4])
glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash) glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash)
} }
@ -517,7 +522,7 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common
// Retrieve all the pending transactions and sort by account and by nonce // Retrieve all the pending transactions and sort by account and by nonce
pending := make(map[common.Address]types.Transactions) pending := make(map[common.Address]types.Transactions)
for _, tx := range self.pending { for _, tx := range self.pending {
account, _ := tx.From() account, _ := types.Sender(self.signer, tx)
pending[account] = append(pending[account], tx) pending[account] = append(pending[account], tx)
} }
// There are no queued transactions in a light pool, just return an empty map // There are no queued transactions in a light pool, just return an empty map

View File

@ -74,7 +74,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
func TestTxPool(t *testing.T) { func TestTxPool(t *testing.T) {
for i, _ := range testTx { for i, _ := range testTx {
testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(types.HomesteadSigner{}, testBankKey)
} }
var ( var (
@ -87,7 +87,8 @@ func TestTxPool(t *testing.T) {
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
// Assemble the test environment // Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux) blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
gchain, _ := core.GenerateChain(nil, genesis, sdb, poolTestBlocks, txPoolTestChainGen) chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
if _, err := blockchain.InsertChain(gchain); err != nil { if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err) panic(err)
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -34,7 +35,7 @@ import (
type VMEnv struct { type VMEnv struct {
vm.Environment vm.Environment
ctx context.Context ctx context.Context
chainConfig *core.ChainConfig chainConfig *params.ChainConfig
evm *vm.EVM evm *vm.EVM
state *VMState state *VMState
header *types.Header header *types.Header
@ -45,7 +46,7 @@ type VMEnv struct {
} }
// NewEnv creates a new execution environment based on an ODR capable light state // NewEnv creates a new execution environment based on an ODR capable light state
func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv { func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv {
env := &VMEnv{ env := &VMEnv{
chainConfig: chainConfig, chainConfig: chainConfig,
chain: chain, chain: chain,
@ -58,17 +59,17 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfi
return env return env
} }
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig } func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
func (self *VMEnv) Vm() vm.Vm { return self.evm } func (self *VMEnv) Vm() vm.Vm { return self.evm }
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } func (self *VMEnv) Origin() common.Address { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
func (self *VMEnv) Time() *big.Int { return self.header.Time } func (self *VMEnv) Time() *big.Int { return self.header.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
func (self *VMEnv) Db() vm.Database { return self.state } func (self *VMEnv) Db() vm.Database { return self.state }
func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) GetHash(n uint64) common.Hash { func (self *VMEnv) GetHash(n uint64) common.Hash {
for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
if header.Number.Uint64() == n { if header.Number.Uint64() == n {

View File

@ -62,7 +62,7 @@ type Miner struct {
shouldStart int32 // should start indicates whether we should start after sync shouldStart int32 // should start indicates whether we should start after sync
} }
func New(eth Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner { func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
miner := &Miner{ miner := &Miner{
eth: eth, eth: eth,
mux: mux, mux: mux,

View File

@ -63,7 +63,9 @@ type uint64RingBuffer struct {
// Work is the workers current environment and holds // Work is the workers current environment and holds
// all of the current state information // all of the current state information
type Work struct { type Work struct {
config *core.ChainConfig config *params.ChainConfig
signer types.Signer
state *state.StateDB // apply state changes here state *state.StateDB // apply state changes here
ancestors *set.Set // ancestor set (used for checking uncle parent validity) ancestors *set.Set // ancestor set (used for checking uncle parent validity)
family *set.Set // family set (used for checking uncle invalidity) family *set.Set // family set (used for checking uncle invalidity)
@ -90,7 +92,7 @@ type Result struct {
// worker is the main object which takes care of applying messages to the new state // worker is the main object which takes care of applying messages to the new state
type worker struct { type worker struct {
config *core.ChainConfig config *params.ChainConfig
mu sync.Mutex mu sync.Mutex
@ -128,7 +130,7 @@ type worker struct {
fullValidation bool fullValidation bool
} }
func newWorker(config *core.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker { func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
worker := &worker{ worker := &worker{
config: config, config: config,
eth: eth, eth: eth,
@ -235,7 +237,7 @@ func (self *worker) update() {
if atomic.LoadInt32(&self.mining) == 0 { if atomic.LoadInt32(&self.mining) == 0 {
self.currentMu.Lock() self.currentMu.Lock()
acc, _ := ev.Tx.From() acc, _ := types.Sender(self.current.signer, ev.Tx)
txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}} txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}}
txset := types.NewTransactionsByPriceAndNonce(txs) txset := types.NewTransactionsByPriceAndNonce(txs)
@ -276,7 +278,7 @@ func (self *worker) wait() {
} }
go self.mux.Post(core.NewMinedBlockEvent{Block: block}) go self.mux.Post(core.NewMinedBlockEvent{Block: block})
} else { } else {
work.state.Commit() work.state.Commit(self.config.IsEIP158(block.Number()))
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil { if parent == nil {
glog.V(logger.Error).Infoln("Invalid block found during mining") glog.V(logger.Error).Infoln("Invalid block found during mining")
@ -367,6 +369,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
} }
work := &Work{ work := &Work{
config: self.config, config: self.config,
signer: types.NewEIP155Signer(self.config.ChainId),
state: state, state: state,
ancestors: set.New(), ancestors: set.New(),
family: set.New(), family: set.New(),
@ -528,7 +531,7 @@ func (self *worker) commitNewWork() {
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
// commit state root after all state transitions. // commit state root after all state transitions.
core.AccumulateRewards(work.state, header, uncles) core.AccumulateRewards(work.state, header, uncles)
header.Root = work.state.IntermediateRoot() header.Root = work.state.IntermediateRoot(self.config.IsEIP158(header.Number))
} }
// create the new block whose nonce will be mined. // create the new block whose nonce will be mined.
@ -570,7 +573,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
} }
// Error may be ignored here. The error has already been checked // Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool. // during transaction acceptance is the transaction pool.
from, _ := tx.From() //
// We use the eip155 signer regardless of the current hf.
from, _ := types.Sender(env.signer, tx)
// Check whether the tx is replay protected. If we're not in the EIP155 hf
// phase, start ignoring the sender until we do.
if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
glog.V(logger.Detail).Infof("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash())
txs.Pop()
continue
}
// Ignore any transactions (and accounts subsequently) with low gas limits // Ignore any transactions (and accounts subsequently) with low gas limits
if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) { if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
@ -620,14 +633,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) { func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
snap := env.state.Snapshot() snap := env.state.Snapshot()
// this is a bit of a hack to force jit for the miners receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{})
config := env.config.VmConfig
if !(config.EnableJit && config.ForceJit) {
config.EnableJit = false
}
config.ForceJit = false // disable forcing jit
receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
if err != nil { if err != nil {
env.state.RevertToSnapshot(snap) env.state.RevertToSnapshot(snap)
return err, nil return err, nil

112
params/config.go Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// ChainConfig is the core config which determines the blockchain settings.
//
// ChainConfig is stored in the database on a per block basis. This means
// that any network, identified by its genesis block, can have its own
// set of configuration options.
type ChainConfig struct {
ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection
HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
EIP150Block *big.Int `json:"eip150Block"` // EIP150 HF block (nil = no fork)
EIP150Hash common.Hash `json:"eip150Hash"` // EIP150 HF hash (fast sync aid)
EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
}
var (
TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
TestRules = TestChainConfig.Rules(new(big.Int))
)
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
if c.HomesteadBlock == nil || num == nil {
return false
}
return num.Cmp(c.HomesteadBlock) >= 0
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
func (c *ChainConfig) GasTable(num *big.Int) GasTable {
if num == nil {
return GasTableHomestead
}
switch {
case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
return GasTableEIP158
case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
return GasTableHomesteadGasRepriceFork
default:
return GasTableHomestead
}
}
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
if c.EIP150Block == nil || num == nil {
return false
}
return num.Cmp(c.EIP150Block) >= 0
}
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
if c.EIP155Block == nil || num == nil {
return false
}
return num.Cmp(c.EIP155Block) >= 0
}
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
if c.EIP158Block == nil || num == nil {
return false
}
return num.Cmp(c.EIP158Block) >= 0
}
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
// that do not have or require information about the block.
//
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainId *big.Int
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
}
func (c *ChainConfig) Rules(num *big.Int) Rules {
return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)}
}

View File

@ -26,6 +26,8 @@ type GasTable struct {
Calls *big.Int Calls *big.Int
Suicide *big.Int Suicide *big.Int
ExpByte *big.Int
// CreateBySuicide occurs when the // CreateBySuicide occurs when the
// refunded account is one that does // refunded account is one that does
// not exist. This logic is similar // not exist. This logic is similar
@ -44,6 +46,7 @@ var (
SLoad: big.NewInt(50), SLoad: big.NewInt(50),
Calls: big.NewInt(40), Calls: big.NewInt(40),
Suicide: big.NewInt(0), Suicide: big.NewInt(0),
ExpByte: big.NewInt(10),
// explicitly set to nil to indicate // explicitly set to nil to indicate
// this rule does not apply to homestead. // this rule does not apply to homestead.
@ -52,6 +55,8 @@ var (
// GasTableHomestead contain the gas re-prices for // GasTableHomestead contain the gas re-prices for
// the homestead phase. // the homestead phase.
//
// TODO rename to GasTableEIP150
GasTableHomesteadGasRepriceFork = GasTable{ GasTableHomesteadGasRepriceFork = GasTable{
ExtcodeSize: big.NewInt(700), ExtcodeSize: big.NewInt(700),
ExtcodeCopy: big.NewInt(700), ExtcodeCopy: big.NewInt(700),
@ -59,6 +64,19 @@ var (
SLoad: big.NewInt(200), SLoad: big.NewInt(200),
Calls: big.NewInt(700), Calls: big.NewInt(700),
Suicide: big.NewInt(5000), Suicide: big.NewInt(5000),
ExpByte: big.NewInt(10),
CreateBySuicide: big.NewInt(25000),
}
GasTableEIP158 = GasTable{
ExtcodeSize: big.NewInt(700),
ExtcodeCopy: big.NewInt(700),
Balance: big.NewInt(400),
SLoad: big.NewInt(200),
Calls: big.NewInt(700),
Suicide: big.NewInt(5000),
ExpByte: big.NewInt(50),
CreateBySuicide: big.NewInt(25000), CreateBySuicide: big.NewInt(25000),
} }

View File

@ -14,9 +14,6 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// DO NOT EDIT!!!
// AUTOGENERATED FROM generators/defaults.go
package params package params
import "math/big" import "math/big"
@ -72,4 +69,5 @@ var (
MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
MaxCodeSize = 24576
) )

View File

@ -34,4 +34,7 @@ var (
TestNetHomesteadGasRepriceHash = common.HexToHash("0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145") // Testnet gas reprice block hash (used by fast sync) TestNetHomesteadGasRepriceHash = common.HexToHash("0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145") // Testnet gas reprice block hash (used by fast sync)
MainNetHomesteadGasRepriceHash = common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0") // Mainnet gas reprice block hash (used by fast sync) MainNetHomesteadGasRepriceHash = common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0") // Mainnet gas reprice block hash (used by fast sync)
TestNetSpuriousDragon = big.NewInt(3000000)
MainNetSpuriousDragon = big.NewInt(3000000)
) )

View File

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -170,7 +171,7 @@ func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *Blo
core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64()) core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64())
core.WriteHeadBlockHash(db, test.Genesis.Hash()) core.WriteHeadBlockHash(db, test.Genesis.Hash())
evmux := new(event.TypeMux) evmux := new(event.TypeMux)
config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, HomesteadGasRepriceBlock: gasPriceFork} config := &params.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux) chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux)
if err != nil { if err != nil {
return err return err
@ -228,7 +229,7 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
} }
} }
root, err := statedb.Commit() root, err := statedb.Commit(false)
if err != nil { if err != nil {
return nil, fmt.Errorf("error writing state: %v", err) return nil, fmt.Errorf("error writing state: %v", err)
} }

0
tests/files/ABITests/basic_abi_tests.json Executable file → Normal file
View File

0
tests/files/BasicTests/blockgenesistest.json Executable file → Normal file
View File

0
tests/files/BasicTests/crypto.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficulty.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficultyCustomHomestead.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficultyFrontier.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficultyHomestead.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficultyMorden.json Executable file → Normal file
View File

0
tests/files/BasicTests/difficultyOlimpic.json Executable file → Normal file
View File

0
tests/files/BasicTests/genesishashestest.json Executable file → Normal file
View File

0
tests/files/BasicTests/hexencodetest.json Executable file → Normal file
View File

0
tests/files/BasicTests/keyaddrtest.json Executable file → Normal file
View File

0
tests/files/BasicTests/txtest.json Executable file → Normal file
View File

View File

@ -0,0 +1,4 @@
Rules for .json tests execution in this folder:
All blocks starting from #0 are on Homestead+EIP150 rules
No Dao Transition rules applied

View File

@ -0,0 +1,644 @@
{
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideFirst" : {
"blocks" : [
{
"blockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
"gasLimit" : "0x0573e3",
"gasUsed" : "0x021efa",
"hash" : "8086802b019efc2bca969f14c1ced66661ff0250481dcfbaa609c60f0d490c34",
"mixHash" : "0f3f1d2ad01778b1b2c6c307df2f89dfc670b5efc82c0f8aef87a509e602997b",
"nonce" : "c29fac11db33446c",
"number" : "0x01",
"parentHash" : "6b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280af",
"receiptTrie" : "bb6c4ae4ebcbc88ae8357320da84cc4e3cbcd7d8e23324b4a2d9646680e65d44",
"stateRoot" : "96860dd0661d97a7f0d394ebc3505f9cb804be725da9a2b7800ab3f73c3e17fc",
"timestamp" : "0x580223b5",
"transactionsTrie" : "7ae056a6d50cfeb8d04816bc1d1e7751f4e054e04d9fde05f5ca200fa0c85b1a",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"rlp" : "0xf904a8f901faa06b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280afa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a096860dd0661d97a7f0d394ebc3505f9cb804be725da9a2b7800ab3f73c3e17fca07ae056a6d50cfeb8d04816bc1d1e7751f4e054e04d9fde05f5ca200fa0c85b1aa0bb6c4ae4ebcbc88ae8357320da84cc4e3cbcd7d8e23324b4a2d9646680e65d44b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001830573e383021efa84580223b580a00f3f1d2ad01778b1b2c6c307df2f89dfc670b5efc82c0f8aef87a509e602997b88c29fac11db33446cf902a7f85f800a82cb2094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba02609a830fd417f9e998391145c3e00efda383fd5ac9e67154a94c9a58ba57eaea00826134c963655d5f0d3c7b6e66a2978cd4b9e99e555d3d8540e60c0291b35ddf85f010a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca054b220ad38df2c2f927f6db93047e2fd19ed3d4fa3263c64db555529b00caddca0688f6a99a0a02850ebe5015a2bbacd780a236dffc2cf41069c7e9f374e618310f85f020a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0739f7287fe4c8c4d41a9721f7c7dca156a70e07c3bc58ac8680cc03add73cc5da056909c94e76719d959fa30679f1080431395f4b85f1fc011f2176ad9119f7dccf85f030a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca09a6b71ffd5ca40339dc032244b33b9dcee5c6c2f5a6519ccb695a959dde6a579a03003f276fa97709ae630cc53d301441e4527ab9645da02053676990943c0f73ef85f040a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca08070f1c4c61c8a2b8f6f814e08a0460dec7fd337e5fde990ad157239c92a7b8fa051dc860feae88e8851be7c7d9b3665d4185b6b85510bdb9426eb9806d0e3d5f0f85f050a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca016886934bf97dc78307bc6d4ad150255d15531043ac7e8073c599dc7903dbd4aa0413ba95502d806757c7b273f018904f19d5c0d441e3547002a387f0e55c4f406f85f060a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca08cdece94e5a6f5a3ea7b3962db6e623efc3c17b8668b94975657078b436c19f1a04453797459a63ca64d238328d86756995b688b4239e62c686aeb6a4e8003f0b8c0",
"transactions" : [
{
"data" : "0x",
"gasLimit" : "0xcb20",
"gasPrice" : "0x0a",
"nonce" : "0x00",
"r" : "0x2609a830fd417f9e998391145c3e00efda383fd5ac9e67154a94c9a58ba57eae",
"s" : "0x0826134c963655d5f0d3c7b6e66a2978cd4b9e99e555d3d8540e60c0291b35dd",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x01",
"r" : "0x54b220ad38df2c2f927f6db93047e2fd19ed3d4fa3263c64db555529b00caddc",
"s" : "0x688f6a99a0a02850ebe5015a2bbacd780a236dffc2cf41069c7e9f374e618310",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x02",
"r" : "0x739f7287fe4c8c4d41a9721f7c7dca156a70e07c3bc58ac8680cc03add73cc5d",
"s" : "0x56909c94e76719d959fa30679f1080431395f4b85f1fc011f2176ad9119f7dcc",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x03",
"r" : "0x9a6b71ffd5ca40339dc032244b33b9dcee5c6c2f5a6519ccb695a959dde6a579",
"s" : "0x3003f276fa97709ae630cc53d301441e4527ab9645da02053676990943c0f73e",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x04",
"r" : "0x8070f1c4c61c8a2b8f6f814e08a0460dec7fd337e5fde990ad157239c92a7b8f",
"s" : "0x51dc860feae88e8851be7c7d9b3665d4185b6b85510bdb9426eb9806d0e3d5f0",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x05",
"r" : "0x16886934bf97dc78307bc6d4ad150255d15531043ac7e8073c599dc7903dbd4a",
"s" : "0x413ba95502d806757c7b273f018904f19d5c0d441e3547002a387f0e55c4f406",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x06",
"r" : "0x8cdece94e5a6f5a3ea7b3962db6e623efc3c17b8668b94975657078b436c19f1",
"s" : "0x4453797459a63ca64d238328d86756995b688b4239e62c686aeb6a4e8003f0b8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
}
],
"uncleHeaders" : [
]
}
],
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x057288",
"gasUsed" : "0x00",
"hash" : "6b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280af",
"mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0102030405060708",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083057288808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0",
"lastblockhash" : "8086802b019efc2bca969f14c1ced66661ff0250481dcfbaa609c60f0d490c34",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x45639182450935c4",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8cedf6ae00",
"code" : "0x",
"nonce" : "0x07",
"storage" : {
}
},
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x3c",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
}
},
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideFirst2" : {
"blocks" : [
{
"blockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
"gasLimit" : "0x023ec6",
"gasUsed" : "0x01f018",
"hash" : "7f7b5aa2c8b0c530c860c294e1c68ce1da99e19f8adc9db3a39650d12e820cc2",
"mixHash" : "067968b01dfe7bd172a87f8380db26a013f8bc37147a406ba2ec67d2400a1265",
"nonce" : "c196d1163d69e2bb",
"number" : "0x01",
"parentHash" : "ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae",
"receiptTrie" : "516f24d9989eb3dec28434a8f1667a42342f98adb2524b980b9f116f9e93e487",
"stateRoot" : "d6c172507a4e3d5977e652d294075e0d35469808ded3843d62daa63f28281236",
"timestamp" : "0x580223b8",
"transactionsTrie" : "50f0f01320e78f4ea013368304ca412fd36cb758cd051a717378cc8dd18b871b",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"rlp" : "0xf90447f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0d6c172507a4e3d5977e652d294075e0d35469808ded3843d62daa63f28281236a050f0f01320e78f4ea013368304ca412fd36cb758cd051a717378cc8dd18b871ba0516f24d9989eb3dec28434a8f1667a42342f98adb2524b980b9f116f9e93e487b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec68301f01884580223b880a0067968b01dfe7bd172a87f8380db26a013f8bc37147a406ba2ec67d2400a126588c196d1163d69e2bbf90246f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506c0",
"transactions" : [
{
"data" : "0x",
"gasLimit" : "0x55f0",
"gasPrice" : "0x0a",
"nonce" : "0x00",
"r" : "0x575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecd",
"s" : "0x6baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0x5208",
"gasPrice" : "0x0a",
"nonce" : "0x01",
"r" : "0x4fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5b",
"s" : "0x17bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192e",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0x5208",
"gasPrice" : "0x0a",
"nonce" : "0x02",
"r" : "0x04377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458ada",
"s" : "0x53a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0x5208",
"gasPrice" : "0x0a",
"nonce" : "0x03",
"r" : "0x4fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615",
"s" : "0x651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0x5208",
"gasPrice" : "0x0a",
"nonce" : "0x04",
"r" : "0x78e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567d",
"s" : "0x13254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198dd",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0x5208",
"gasPrice" : "0x0a",
"nonce" : "0x05",
"r" : "0xa7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54",
"s" : "0x534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
}
],
"uncleHeaders" : [
]
}
],
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x023e38",
"gasUsed" : "0x00",
"hash" : "ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae",
"mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0102030405060708",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0",
"lastblockhash" : "7f7b5aa2c8b0c530c860c294e1c68ce1da99e19f8adc9db3a39650d12e820cc2",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x45639182450760f0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a99ec9ede",
"code" : "0x",
"nonce" : "0x06",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
},
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x32",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
}
},
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideLast" : {
"blocks" : [
{
"blockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
"gasLimit" : "0x057224",
"gasUsed" : "0x021efa",
"hash" : "2eb60f05a7c1de9324272c530a036f9d7d4961bd0624a4305332688ee4f3a1ad",
"mixHash" : "46f46431ee1ccce22ed8a9ba68a376b13fdf11049fde4b0673ff9b7cb69a2113",
"nonce" : "7174ad3c7b1386db",
"number" : "0x01",
"parentHash" : "6b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280af",
"receiptTrie" : "2244456c1f7bdf7204250dfa2a2a1474014a9f50477ae0106dcf2dda6227a0f1",
"stateRoot" : "96860dd0661d97a7f0d394ebc3505f9cb804be725da9a2b7800ab3f73c3e17fc",
"timestamp" : "0x580223ba",
"transactionsTrie" : "f326b89e33ec4068bb300de24bb45f2a81e59333badd5b858e60e7239e984a00",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"rlp" : "0xf904a8f901faa06b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280afa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a096860dd0661d97a7f0d394ebc3505f9cb804be725da9a2b7800ab3f73c3e17fca0f326b89e33ec4068bb300de24bb45f2a81e59333badd5b858e60e7239e984a00a02244456c1f7bdf7204250dfa2a2a1474014a9f50477ae0106dcf2dda6227a0f1b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018305722483021efa84580223ba80a046f46431ee1ccce22ed8a9ba68a376b13fdf11049fde4b0673ff9b7cb69a2113887174ad3c7b1386dbf902a7f85f800a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0d5f556ab52e7baa68c0312f2482ec84288d55fec2e3feb617e11859269aea1f7a0546a329bf1ab773dcec4861c7341bcd8de5a0f3c75c37230a101cd0c8f763155f85f010a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca054b220ad38df2c2f927f6db93047e2fd19ed3d4fa3263c64db555529b00caddca0688f6a99a0a02850ebe5015a2bbacd780a236dffc2cf41069c7e9f374e618310f85f020a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0739f7287fe4c8c4d41a9721f7c7dca156a70e07c3bc58ac8680cc03add73cc5da056909c94e76719d959fa30679f1080431395f4b85f1fc011f2176ad9119f7dccf85f030a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca09a6b71ffd5ca40339dc032244b33b9dcee5c6c2f5a6519ccb695a959dde6a579a03003f276fa97709ae630cc53d301441e4527ab9645da02053676990943c0f73ef85f040a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca08070f1c4c61c8a2b8f6f814e08a0460dec7fd337e5fde990ad157239c92a7b8fa051dc860feae88e8851be7c7d9b3665d4185b6b85510bdb9426eb9806d0e3d5f0f85f050a82c73894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca016886934bf97dc78307bc6d4ad150255d15531043ac7e8073c599dc7903dbd4aa0413ba95502d806757c7b273f018904f19d5c0d441e3547002a387f0e55c4f406f85f060a82cb2094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0fac540b907e8ad85e503830b3ebdd35336fc535102bde0790987cd0ee253d876a0668bc7331874caefbb7d457161632482293e7df4c90c84a254850cabc13a83eac0",
"transactions" : [
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x00",
"r" : "0xd5f556ab52e7baa68c0312f2482ec84288d55fec2e3feb617e11859269aea1f7",
"s" : "0x546a329bf1ab773dcec4861c7341bcd8de5a0f3c75c37230a101cd0c8f763155",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x01",
"r" : "0x54b220ad38df2c2f927f6db93047e2fd19ed3d4fa3263c64db555529b00caddc",
"s" : "0x688f6a99a0a02850ebe5015a2bbacd780a236dffc2cf41069c7e9f374e618310",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x02",
"r" : "0x739f7287fe4c8c4d41a9721f7c7dca156a70e07c3bc58ac8680cc03add73cc5d",
"s" : "0x56909c94e76719d959fa30679f1080431395f4b85f1fc011f2176ad9119f7dcc",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x03",
"r" : "0x9a6b71ffd5ca40339dc032244b33b9dcee5c6c2f5a6519ccb695a959dde6a579",
"s" : "0x3003f276fa97709ae630cc53d301441e4527ab9645da02053676990943c0f73e",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x04",
"r" : "0x8070f1c4c61c8a2b8f6f814e08a0460dec7fd337e5fde990ad157239c92a7b8f",
"s" : "0x51dc860feae88e8851be7c7d9b3665d4185b6b85510bdb9426eb9806d0e3d5f0",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xc738",
"gasPrice" : "0x0a",
"nonce" : "0x05",
"r" : "0x16886934bf97dc78307bc6d4ad150255d15531043ac7e8073c599dc7903dbd4a",
"s" : "0x413ba95502d806757c7b273f018904f19d5c0d441e3547002a387f0e55c4f406",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1c",
"value" : "0x0a"
},
{
"data" : "0x",
"gasLimit" : "0xcb20",
"gasPrice" : "0x0a",
"nonce" : "0x06",
"r" : "0xfac540b907e8ad85e503830b3ebdd35336fc535102bde0790987cd0ee253d876",
"s" : "0x668bc7331874caefbb7d457161632482293e7df4c90c84a254850cabc13a83ea",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
}
],
"uncleHeaders" : [
]
}
],
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x057288",
"gasUsed" : "0x00",
"hash" : "6b68d5db45371f617741815045c95862f0fbcb659c1eb25dda1d63b15d7280af",
"mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0102030405060708",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083057288808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0",
"lastblockhash" : "2eb60f05a7c1de9324272c530a036f9d7d4961bd0624a4305332688ee4f3a1ad",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x45639182450935c4",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8cedf6ae00",
"code" : "0x",
"nonce" : "0x07",
"storage" : {
}
},
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x3c",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
}
},
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideLast2" : {
"blocks" : [
{
"rlp" : "0xf904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a053f912b64765458bba76c0978a8e5ecd90417d527ea20f55689108400763c8a039b55901ee38a65fa27c7d60137fd431afcf6a7615746ae9501e7cf0ca68bd11a071ba8e7c3c6ee55bfb14c3119ca5b4ceb032cfad51952e3a116a449240b38aa4b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023dd48302422084580223bb80a04b470f8cc54688c5989133701126272e6c272a4a7853a5d05b27adc94460f50b88830f7ed5cbc7d1f9f902a7f85f800a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba01117bd549fe17f8383012bf168dabd9e70851fdf2f332e5bfea89318dddd6c77a001364d3a0e23f462052127c53a5473c428e2211806c927601562f840eb6b899cf85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0c40c1300a7cc64b842c9421a6c6e985b5531020d1a26c82f9c6a5200154e91dfa052c28fc6dc0dad9ea23fcce6510a9dc23b9903b1b19a126ac25f77a195b50f83c0"
}
],
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x023e38",
"gasUsed" : "0x00",
"hash" : "ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae",
"mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0102030405060708",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0",
"lastblockhash" : "ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae",
"postState" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
}
},
"SuicideTransaction" : {
"blocks" : [
{
"blockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
"gasLimit" : "0x01e8c1",
"gasUsed" : "0x32ca",
"hash" : "a3eba1779c002a8e02f41bab6dea595cbad0e44d5c3fbbdd0ad908190c34c63d",
"mixHash" : "e13d00455c6d34792fcd2f2036744f822e2f269e8bc6f5a7389307812db0711d",
"nonce" : "97bf5b2844593304",
"number" : "0x01",
"parentHash" : "926fddd6a0f69ff8c29833222a7150b9d50f759bda6d50e4c9ea3af6c4ba921d",
"receiptTrie" : "10910901e8fd125dffe40187af7dae0d71bbf63f0fed0bb84bedc624586060f7",
"stateRoot" : "483344fadf21e2fc01ab19a4041532edc23747d017bb386edcc0859ba225fe0d",
"timestamp" : "0x580223bd",
"transactionsTrie" : "f0162cdb94cda8b79bf634c6093931008a12d1e4922821a992e34511b83ed0d5",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"rlp" : "0xf90261f901f9a0926fddd6a0f69ff8c29833222a7150b9d50f759bda6d50e4c9ea3af6c4ba921da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0483344fadf21e2fc01ab19a4041532edc23747d017bb386edcc0859ba225fe0da0f0162cdb94cda8b79bf634c6093931008a12d1e4922821a992e34511b83ed0d5a010910901e8fd125dffe40187af7dae0d71bbf63f0fed0bb84bedc624586060f7b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018301e8c18232ca84580223bd80a0e13d00455c6d34792fcd2f2036744f822e2f269e8bc6f5a7389307812db0711d8897bf5b2844593304f862f860800a830186a094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0444ed2cb67c1cce2c37add4bef48d3dda9ef05e28eaf023006036a4c5f7c96b0a00c56b07bfc50471d458e67923c91108b90cb7bba23f4d373f0a75632a413bd84c0",
"transactions" : [
{
"data" : "0x",
"gasLimit" : "0x0186a0",
"gasPrice" : "0x0a",
"nonce" : "0x00",
"r" : "0x444ed2cb67c1cce2c37add4bef48d3dda9ef05e28eaf023006036a4c5f7c96b0",
"s" : "0x0c56b07bfc50471d458e67923c91108b90cb7bba23f4d373f0a75632a413bd84",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"v" : "0x1b",
"value" : "0x0a"
}
],
"uncleHeaders" : [
]
}
],
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x01e848",
"gasUsed" : "0x00",
"hash" : "926fddd6a0f69ff8c29833222a7150b9d50f759bda6d50e4c9ea3af6c4ba921d",
"mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0102030405060708",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808301e848808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0",
"lastblockhash" : "a3eba1779c002a8e02f41bab6dea595cbad0e44d5c3fbbdd0ad908190c34c63d",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x4563918244f5fbe4",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8cee09e81c",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x4a723dc6b40b8a9a000000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x02540be400",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More