core/types, params: EIP#155
This commit is contained in:
@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
||||
toaddr := common.Address{}
|
||||
data := make([]byte, nbytes)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
tx, _ = tx.SignECDSA(ringKeys[from])
|
||||
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from])
|
||||
gen.AddTx(tx)
|
||||
from = to
|
||||
}
|
||||
|
@ -634,17 +634,19 @@ func (self *BlockChain) Rollback(chain []common.Hash) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
for j := 0; j < len(receipts); j++ {
|
||||
// The transaction hash can be retrieved from the transaction itself
|
||||
receipts[j].TxHash = transactions[j].Hash()
|
||||
|
||||
tx, _ := transactions[j].AsMessage(signer)
|
||||
// The contract address can be derived from the transaction itself
|
||||
if MessageCreatesContract(transactions[j]) {
|
||||
from, _ := transactions[j].From()
|
||||
receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce())
|
||||
if MessageCreatesContract(tx) {
|
||||
receipts[j].ContractAddress = crypto.CreateAddress(tx.From(), tx.Nonce())
|
||||
}
|
||||
// The used gas can be calculated based on previous receipts
|
||||
if j == 0 {
|
||||
@ -666,6 +668,7 @@ func SetReceiptsData(block *types.Block, receipts types.Receipts) {
|
||||
|
||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||
// transaction and receipt data.
|
||||
// XXX should this be moved to the test?
|
||||
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
||||
self.wg.Add(1)
|
||||
defer self.wg.Done()
|
||||
@ -705,7 +708,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||
continue
|
||||
}
|
||||
// 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
|
||||
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||
errs[index] = fmt.Errorf("failed to write block body: %v", err)
|
||||
|
@ -711,6 +711,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||
funds = big.NewInt(1000000000)
|
||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||
)
|
||||
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
|
||||
block.SetCoinbase(common.Address{0x00})
|
||||
@ -718,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
||||
if i%3 == 2 {
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
@ -872,6 +873,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
db, _ = ethdb.NewMemDatabase()
|
||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||
)
|
||||
genesis := WriteGenesisBlockForTesting(db,
|
||||
GenesisAccount{addr1, big.NewInt(1000000)},
|
||||
@ -881,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
|
||||
// Create two transactions shared between the chains:
|
||||
// - postponed: transaction included at a later block 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)
|
||||
swapped, _ := types.NewTransaction(1, 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(signer, key1)
|
||||
|
||||
// Create two transactions that will be dropped by the forked chain:
|
||||
// - pastDrop: transaction dropped retroactively from a past block
|
||||
@ -898,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) {
|
||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
|
||||
switch i {
|
||||
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(postponed) // This transaction will be postponed till block #3 in the fork
|
||||
|
||||
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(swapped) // This transaction will be swapped out at the exact height
|
||||
@ -923,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) {
|
||||
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||
switch i {
|
||||
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
|
||||
|
||||
case 2:
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
@ -980,7 +982,8 @@ func TestLogReorgs(t *testing.T) {
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
db, _ = ethdb.NewMemDatabase()
|
||||
// this code generates a log
|
||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||
)
|
||||
genesis := WriteGenesisBlockForTesting(db,
|
||||
GenesisAccount{addr1, big.NewInt(10000000000000)},
|
||||
@ -992,7 +995,7 @@ func TestLogReorgs(t *testing.T) {
|
||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||
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 {
|
||||
t.Fatalf("failed to create tx: %v", err)
|
||||
}
|
||||
@ -1020,6 +1023,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
|
||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||
)
|
||||
|
||||
evmux := &event.TypeMux{}
|
||||
@ -1031,7 +1035,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||
}
|
||||
|
||||
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 {
|
||||
gen.OffsetTime(-1)
|
||||
}
|
||||
@ -1128,3 +1132,105 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||
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 = ¶ms.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 = ¶ms.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)
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ func ExampleGenerateChain() {
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
db, _ = ethdb.NewMemDatabase()
|
||||
signer = types.HomesteadSigner{}
|
||||
)
|
||||
|
||||
chainConfig := ¶ms.ChainConfig{
|
||||
@ -54,13 +55,13 @@ func ExampleGenerateChain() {
|
||||
switch i {
|
||||
case 0:
|
||||
// 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)
|
||||
case 1:
|
||||
// In block 2, addr1 sends some more ether to addr2.
|
||||
// addr2 passes it on to addr3.
|
||||
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1)
|
||||
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
|
||||
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(signer, key2)
|
||||
gen.AddTx(tx1)
|
||||
gen.AddTx(tx2)
|
||||
case 2:
|
||||
|
@ -17,6 +17,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
@ -72,10 +73,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
}
|
||||
// Iterate over and process the individual 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)
|
||||
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
||||
if err != nil {
|
||||
return nil, nil, totalUsedGas, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
receipts = append(receipts, receipt)
|
||||
allLogs = append(allLogs, logs...)
|
||||
@ -91,7 +96,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||
// execution of the state transition phase.
|
||||
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 {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@ -101,9 +111,8 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s
|
||||
receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
|
||||
receipt.TxHash = tx.Hash()
|
||||
receipt.GasUsed = new(big.Int).Set(gas)
|
||||
if MessageCreatesContract(tx) {
|
||||
from, _ := tx.From()
|
||||
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
|
||||
if MessageCreatesContract(msg) {
|
||||
receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce())
|
||||
}
|
||||
|
||||
logs := statedb.GetLogs(tx.Hash())
|
||||
|
@ -62,8 +62,8 @@ type StateTransition struct {
|
||||
|
||||
// Message represents a message sent to a contract.
|
||||
type Message interface {
|
||||
From() (common.Address, error)
|
||||
FromFrontier() (common.Address, error)
|
||||
From() common.Address
|
||||
//FromFrontier() (common.Address, error)
|
||||
To() *common.Address
|
||||
|
||||
GasPrice() *big.Int
|
||||
@ -134,23 +134,12 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
|
||||
return ret, gasUsed, err
|
||||
}
|
||||
|
||||
func (self *StateTransition) from() (vm.Account, error) {
|
||||
var (
|
||||
f common.Address
|
||||
err error
|
||||
)
|
||||
if self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) {
|
||||
f, err = self.msg.From()
|
||||
} else {
|
||||
f, err = self.msg.FromFrontier()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (self *StateTransition) from() vm.Account {
|
||||
f := self.msg.From()
|
||||
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 {
|
||||
@ -185,14 +174,11 @@ func (self *StateTransition) buyGas() error {
|
||||
mgas := self.msg.Gas()
|
||||
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
||||
|
||||
sender, err := self.from()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sender := self.from()
|
||||
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())
|
||||
}
|
||||
if err = self.gp.SubGas(mgas); err != nil {
|
||||
if err := self.gp.SubGas(mgas); err != nil {
|
||||
return err
|
||||
}
|
||||
self.addGas(mgas)
|
||||
@ -203,10 +189,7 @@ func (self *StateTransition) buyGas() error {
|
||||
|
||||
func (self *StateTransition) preCheck() (err error) {
|
||||
msg := self.msg
|
||||
sender, err := self.from()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sender := self.from()
|
||||
|
||||
// Make sure this transaction's nonce is correct
|
||||
if msg.CheckNonce() {
|
||||
@ -232,7 +215,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||
return
|
||||
}
|
||||
msg := self.msg
|
||||
sender, _ := self.from() // err checked in preCheck
|
||||
sender := self.from() // err checked in preCheck
|
||||
|
||||
homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber())
|
||||
contractCreation := MessageCreatesContract(msg)
|
||||
@ -282,7 +265,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||
func (self *StateTransition) refundGas() {
|
||||
// Return eth for remaining gas to the sender account,
|
||||
// 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)
|
||||
sender.AddBalance(remaining)
|
||||
|
||||
|
@ -92,6 +92,7 @@ type TxPool struct {
|
||||
eventMux *event.TypeMux
|
||||
events event.Subscription
|
||||
localTx *txSet
|
||||
signer types.Signer
|
||||
mu sync.RWMutex
|
||||
|
||||
pending map[common.Address]*txList // All currently processable transactions
|
||||
@ -108,6 +109,7 @@ type TxPool struct {
|
||||
func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
|
||||
pool := &TxPool{
|
||||
config: config,
|
||||
signer: types.NewEIP155Signer(config.ChainId),
|
||||
pending: make(map[common.Address]*txList),
|
||||
queue: make(map[common.Address]*txList),
|
||||
all: make(map[common.Hash]*types.Transaction),
|
||||
@ -139,8 +141,10 @@ func (pool *TxPool) eventLoop() {
|
||||
switch ev := ev.Data.(type) {
|
||||
case ChainHeadEvent:
|
||||
pool.mu.Lock()
|
||||
if ev.Block != nil && pool.config.IsHomestead(ev.Block.Number()) {
|
||||
pool.homestead = true
|
||||
if ev.Block != nil {
|
||||
if pool.config.IsHomestead(ev.Block.Number()) {
|
||||
pool.homestead = true
|
||||
}
|
||||
}
|
||||
|
||||
pool.resetState()
|
||||
@ -272,7 +276,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||
return err
|
||||
}
|
||||
|
||||
from, err := tx.From()
|
||||
from, err := types.Sender(pool.signer, tx)
|
||||
if err != nil {
|
||||
return ErrInvalidSender
|
||||
}
|
||||
@ -307,7 +311,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||
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 {
|
||||
return ErrIntrinsicGas
|
||||
}
|
||||
@ -336,7 +340,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
|
||||
if to := tx.To(); to != nil {
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
@ -347,7 +351,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
|
||||
// Note, this method assumes the pool lock is held!
|
||||
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
|
||||
// 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 {
|
||||
pool.queue[from] = newTxList(false)
|
||||
}
|
||||
@ -459,7 +463,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||
if !ok {
|
||||
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
|
||||
delete(pool.all, hash)
|
||||
|
@ -32,7 +32,7 @@ import (
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -47,6 +47,10 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||
return newPool, key
|
||||
}
|
||||
|
||||
func deriveSender(tx *types.Transaction) (common.Address, error) {
|
||||
return types.Sender(types.HomesteadSigner{}, tx)
|
||||
}
|
||||
|
||||
func TestInvalidTransactions(t *testing.T) {
|
||||
pool, key := setupTxPool()
|
||||
|
||||
@ -55,7 +59,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||
t.Error("expected", ErrNonExistentAccount)
|
||||
}
|
||||
|
||||
from, _ := tx.From()
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1))
|
||||
if err := pool.Add(tx); err != ErrInsufficientFunds {
|
||||
@ -90,7 +94,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||
func TestTransactionQueue(t *testing.T) {
|
||||
pool, key := setupTxPool()
|
||||
tx := transaction(0, big.NewInt(100), key)
|
||||
from, _ := tx.From()
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000))
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
@ -101,7 +105,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
}
|
||||
|
||||
tx = transaction(1, big.NewInt(100), key)
|
||||
from, _ = tx.From()
|
||||
from, _ = deriveSender(tx)
|
||||
currentState.SetNonce(from, 2)
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
pool.promoteExecutables()
|
||||
@ -117,7 +121,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
tx1 := transaction(0, big.NewInt(100), key)
|
||||
tx2 := transaction(10, big.NewInt(100), key)
|
||||
tx3 := transaction(11, big.NewInt(100), key)
|
||||
from, _ = tx1.From()
|
||||
from, _ = deriveSender(tx1)
|
||||
currentState, _ = pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000))
|
||||
pool.enqueueTx(tx1.Hash(), tx1)
|
||||
@ -137,7 +141,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
func TestRemoveTx(t *testing.T) {
|
||||
pool, key := setupTxPool()
|
||||
tx := transaction(0, big.NewInt(100), key)
|
||||
from, _ := tx.From()
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1))
|
||||
|
||||
@ -161,8 +165,8 @@ func TestRemoveTx(t *testing.T) {
|
||||
func TestNegativeValue(t *testing.T) {
|
||||
pool, key := setupTxPool()
|
||||
|
||||
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key)
|
||||
from, _ := tx.From()
|
||||
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1))
|
||||
if err := pool.Add(tx); err != ErrNegativeValue {
|
||||
@ -209,9 +213,10 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||
}
|
||||
resetState()
|
||||
|
||||
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(key)
|
||||
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(key)
|
||||
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(key)
|
||||
signer := types.HomesteadSigner{}
|
||||
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, 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
|
||||
if err := pool.add(tx1); err != nil {
|
||||
@ -287,7 +292,7 @@ func TestNonceRecovery(t *testing.T) {
|
||||
func TestRemovedTxEvent(t *testing.T) {
|
||||
pool, key := setupTxPool()
|
||||
tx := transaction(0, big.NewInt(1000000), key)
|
||||
from, _ := tx.From()
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000000000000))
|
||||
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
||||
@ -305,7 +310,7 @@ func TestRemovedTxEvent(t *testing.T) {
|
||||
func TestTransactionDropping(t *testing.T) {
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000))
|
||||
@ -369,7 +374,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||
func TestTransactionPostponing(t *testing.T) {
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000))
|
||||
@ -443,7 +448,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||
func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
@ -531,7 +536,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
|
||||
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
@ -555,7 +560,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
|
||||
func TestTransactionPendingLimiting(t *testing.T) {
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
@ -585,7 +590,7 @@ func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLi
|
||||
func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
||||
// Add a batch of transactions to a pool one by one
|
||||
pool1, key1 := setupTxPool()
|
||||
account1, _ := transaction(0, big.NewInt(0), key1).From()
|
||||
account1, _ := deriveSender(transaction(0, big.NewInt(0), key1))
|
||||
state1, _ := pool1.currentState()
|
||||
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
|
||||
pool2, key2 := setupTxPool()
|
||||
account2, _ := transaction(0, big.NewInt(0), key2).From()
|
||||
account2, _ := deriveSender(transaction(0, big.NewInt(0), key2))
|
||||
state2, _ := pool2.currentState()
|
||||
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) {
|
||||
// Add a batch of transactions to a pool one by one
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
state, _ := pool.currentState()
|
||||
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) {
|
||||
// Add a batch of transactions to a pool one by one
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
|
||||
@ -760,7 +765,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||
func BenchmarkPoolInsert(b *testing.B) {
|
||||
// Generate a batch of transactions to enqueue into the pool
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
state, _ := pool.currentState()
|
||||
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) {
|
||||
// Generate a batch of transactions to enqueue into the pool
|
||||
pool, key := setupTxPool()
|
||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
||||
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
|
||||
|
@ -18,6 +18,7 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
@ -51,7 +52,11 @@ func TestBlockEncoding(t *testing.T) {
|
||||
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, _ = 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("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
|
||||
|
||||
|
@ -97,10 +97,12 @@ var unmarshalTransactionTests = map[string]struct {
|
||||
wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"),
|
||||
wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"),
|
||||
},
|
||||
/* TODO skipping this test as this type can not be tested with the current signing approach
|
||||
"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"}`,
|
||||
wantError: ErrInvalidSig,
|
||||
},
|
||||
*/
|
||||
"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"}`,
|
||||
wantError: errMissingTxSignatureFields,
|
||||
@ -122,11 +124,12 @@ func TestUnmarshalTransaction(t *testing.T) {
|
||||
if !checkError(t, name, err, test.wantError) {
|
||||
continue
|
||||
}
|
||||
|
||||
if tx.Hash() != test.wantHash {
|
||||
t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash)
|
||||
continue
|
||||
}
|
||||
from, err := tx.From()
|
||||
from, err := Sender(HomesteadSigner{}, tx)
|
||||
if err != nil {
|
||||
t.Errorf("test %q: From error %v", name, err)
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
@ -36,8 +37,18 @@ var ErrInvalidSig = errors.New("invalid transaction v, r, s values")
|
||||
var (
|
||||
errMissingTxSignatureFields = errors.New("missing required JSON transaction signature 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 {
|
||||
data txdata
|
||||
// caches
|
||||
@ -52,7 +63,7 @@ type txdata struct {
|
||||
Recipient *common.Address `rlp:"nil"` // nil means contract creation
|
||||
Amount *big.Int
|
||||
Payload []byte
|
||||
V byte // signature
|
||||
V *big.Int // signature
|
||||
R, S *big.Int // signature
|
||||
}
|
||||
|
||||
@ -64,40 +75,31 @@ type jsonTransaction struct {
|
||||
Recipient *common.Address `json:"to"`
|
||||
Amount *hexBig `json:"value"`
|
||||
Payload *hexBytes `json:"input"`
|
||||
V *hexUint64 `json:"v"`
|
||||
V *hexBig `json:"v"`
|
||||
R *hexBig `json:"r"`
|
||||
S *hexBig `json:"s"`
|
||||
}
|
||||
|
||||
// NewContractCreation creates a new transaction with no recipient.
|
||||
func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||
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),
|
||||
}}
|
||||
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
|
||||
}
|
||||
|
||||
// NewTransaction creates a new transaction with the given fields.
|
||||
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, nil, amount, gasLimit, gasPrice, data)
|
||||
}
|
||||
|
||||
func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||
if len(data) > 0 {
|
||||
data = common.CopyBytes(data)
|
||||
}
|
||||
d := txdata{
|
||||
AccountNonce: nonce,
|
||||
Recipient: &to,
|
||||
Recipient: to,
|
||||
Payload: data,
|
||||
Amount: new(big.Int),
|
||||
GasLimit: new(big.Int),
|
||||
Price: new(big.Int),
|
||||
V: new(big.Int),
|
||||
R: new(big.Int),
|
||||
S: new(big.Int),
|
||||
}
|
||||
@ -110,9 +112,42 @@ func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice
|
||||
if gasPrice != nil {
|
||||
d.Price.Set(gasPrice)
|
||||
}
|
||||
|
||||
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
|
||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
||||
return rlp.Encode(w, &tx.data)
|
||||
@ -125,12 +160,13 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
||||
if err == nil {
|
||||
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON encodes transactions into the web3 RPC response block format.
|
||||
func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||
hash, v := tx.Hash(), uint64(tx.data.V)
|
||||
hash := tx.Hash()
|
||||
|
||||
return json.Marshal(&jsonTransaction{
|
||||
Hash: &hash,
|
||||
@ -140,7 +176,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||
Recipient: tx.data.Recipient,
|
||||
Amount: (*hexBig)(tx.data.Amount),
|
||||
Payload: (*hexBytes)(&tx.data.Payload),
|
||||
V: (*hexUint64)(&v),
|
||||
V: (*hexBig)(tx.data.V),
|
||||
R: (*hexBig)(tx.data.R),
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
|
||||
return errMissingTxFields
|
||||
}
|
||||
@ -175,7 +219,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||
GasLimit: (*big.Int)(dec.GasLimit),
|
||||
Price: (*big.Int)(dec.Price),
|
||||
Payload: *dec.Payload,
|
||||
V: byte(*dec.V),
|
||||
V: (*big.Int)(dec.V),
|
||||
R: (*big.Int)(dec.R),
|
||||
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.
|
||||
// It does not uniquely identify the transaction.
|
||||
func (tx *Transaction) SigHash() common.Hash {
|
||||
return rlpHash([]interface{}{
|
||||
tx.data.AccountNonce,
|
||||
tx.data.Price,
|
||||
tx.data.GasLimit,
|
||||
tx.data.Recipient,
|
||||
tx.data.Amount,
|
||||
tx.data.Payload,
|
||||
})
|
||||
func (tx *Transaction) SigHash(signer Signer) common.Hash {
|
||||
return signer.Hash(tx)
|
||||
}
|
||||
|
||||
func (tx *Transaction) Size() common.StorageSize {
|
||||
@ -232,6 +269,7 @@ func (tx *Transaction) Size() common.StorageSize {
|
||||
return common.StorageSize(c)
|
||||
}
|
||||
|
||||
/*
|
||||
// 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
|
||||
// signature.
|
||||
@ -247,32 +285,15 @@ func (tx *Transaction) Size() common.StorageSize {
|
||||
// both txs before and after the first homestead block. Signatures
|
||||
// valid in homestead are a subset of valid ones in Frontier)
|
||||
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 {
|
||||
return from.(common.Address), nil
|
||||
}
|
||||
pubkey, err := tx.publicKey(homestead)
|
||||
|
||||
pubkey, err := tx.signer.PublicKey(tx)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
@ -282,6 +303,51 @@ func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
|
||||
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.
|
||||
func (tx *Transaction) Cost() *big.Int {
|
||||
total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit)
|
||||
@ -289,61 +355,18 @@ func (tx *Transaction) Cost() *big.Int {
|
||||
return total
|
||||
}
|
||||
|
||||
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
||||
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) {
|
||||
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) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
|
||||
return tx.data.V, tx.data.R, tx.data.S
|
||||
}
|
||||
|
||||
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
|
||||
if f, err := tx.From(); err != nil {
|
||||
from = "[invalid sender]"
|
||||
if f, err := Sender(signer, tx); err != nil { // derive but don't cache
|
||||
from = "[invalid sender: invalid sig]"
|
||||
} else {
|
||||
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.
|
||||
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 {
|
||||
t.heads[0], t.txs[acc] = txs[0], txs[1:]
|
||||
heap.Fix(&t.heads, 0)
|
||||
@ -501,3 +525,35 @@ func (t *TransactionsByPriceAndNonce) Shift() {
|
||||
func (t *TransactionsByPriceAndNonce) Pop() {
|
||||
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 }
|
||||
|
340
core/types/transaction_signing.go
Normal file
340
core/types/transaction_signing.go
Normal 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))
|
||||
}
|
116
core/types/transaction_signing_test.go
Normal file
116
core/types/transaction_signing_test.go
Normal 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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -46,15 +46,16 @@ var (
|
||||
big.NewInt(1),
|
||||
common.FromHex("5544"),
|
||||
).WithSignature(
|
||||
HomesteadSigner{},
|
||||
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
|
||||
)
|
||||
)
|
||||
|
||||
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())
|
||||
}
|
||||
if rightvrsTx.SigHash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
|
||||
if rightvrsTx.SigHash(HomesteadSigner{}) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
|
||||
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) {
|
||||
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) {
|
||||
@ -88,7 +91,8 @@ func TestRecipientEmpty(t *testing.T) {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
from, err := tx.From()
|
||||
|
||||
from, err := Sender(HomesteadSigner{}, tx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
@ -107,7 +111,7 @@ func TestRecipientNormal(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
from, err := tx.From()
|
||||
from, err := Sender(HomesteadSigner{}, tx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
@ -127,12 +131,14 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
}
|
||||
|
||||
signer := HomesteadSigner{}
|
||||
// Generate a batch of transactions with overlapping values, but shifted nonces
|
||||
groups := map[common.Address]Transactions{}
|
||||
for start, key := range keys {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -148,11 +154,11 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||
break
|
||||
}
|
||||
for i, txi := range txs {
|
||||
fromi, _ := txi.From()
|
||||
fromi, _ := Sender(signer, txi)
|
||||
|
||||
// Make sure the nonce order is valid
|
||||
for j, txj := range txs[i+1:] {
|
||||
fromj, _ := txj.From()
|
||||
fromj, _ := Sender(signer, txj)
|
||||
|
||||
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())
|
||||
@ -161,20 +167,20 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||
// Find the previous and next nonce of this account
|
||||
prev, next := i-1, i+1
|
||||
for j := i - 1; j >= 0; j-- {
|
||||
if fromj, _ := txs[j].From(); fromi == fromj {
|
||||
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
|
||||
prev = j
|
||||
break
|
||||
}
|
||||
}
|
||||
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
|
||||
break
|
||||
}
|
||||
}
|
||||
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
|
||||
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 {
|
||||
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())
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ func NewEnv(config *Config) *Env {
|
||||
}
|
||||
|
||||
func (self *Env) ChainConfig() *params.ChainConfig {
|
||||
return ¶ms.ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int)}
|
||||
return params.TestChainConfig
|
||||
}
|
||||
func (self *Env) Vm() Vm { return self.evm }
|
||||
func (self *Env) Origin() common.Address { return common.Address{} }
|
||||
|
@ -57,7 +57,7 @@ type Config struct {
|
||||
// sets defaults on the config
|
||||
func setDefaults(cfg *Config) {
|
||||
if cfg.ChainConfig == nil {
|
||||
cfg.ChainConfig = ¶ms.ChainConfig{new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int)}
|
||||
cfg.ChainConfig = ¶ms.ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int), new(big.Int), new(big.Int)}
|
||||
}
|
||||
|
||||
if cfg.Difficulty == nil {
|
||||
|
@ -69,7 +69,7 @@ func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockC
|
||||
|
||||
func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
|
||||
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) Coinbase() common.Address { return self.header.Coinbase }
|
||||
func (self *VMEnv) Time() *big.Int { return self.header.Time }
|
||||
|
Reference in New Issue
Block a user