core/types: make transactions immutable
This commit is contained in:
		
				
					committed by
					
						
						Jeffrey Wilcke
					
				
			
			
				
	
			
			
			
						parent
						
							9d8b512b27
						
					
				
				
					commit
					654564e164
				
			@@ -162,27 +162,25 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
 | 
			
		||||
 | 
			
		||||
	// Check the transaction doesn't exceed the current
 | 
			
		||||
	// block limit gas.
 | 
			
		||||
	if pool.gasLimit().Cmp(tx.GasLimit) < 0 {
 | 
			
		||||
	if pool.gasLimit().Cmp(tx.Gas()) < 0 {
 | 
			
		||||
		return ErrGasLimit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Transactions can't be negative. This may never happen
 | 
			
		||||
	// using RLP decoded transactions but may occur if you create
 | 
			
		||||
	// a transaction using the RPC for example.
 | 
			
		||||
	if tx.Amount.Cmp(common.Big0) < 0 {
 | 
			
		||||
	if tx.Value().Cmp(common.Big0) < 0 {
 | 
			
		||||
		return ErrNegativeValue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Transactor should have enough funds to cover the costs
 | 
			
		||||
	// cost == V + GP * GL
 | 
			
		||||
	total := new(big.Int).Mul(tx.Price, tx.GasLimit)
 | 
			
		||||
	total.Add(total, tx.Value())
 | 
			
		||||
	if pool.currentState().GetBalance(from).Cmp(total) < 0 {
 | 
			
		||||
	if pool.currentState().GetBalance(from).Cmp(tx.Cost()) < 0 {
 | 
			
		||||
		return ErrInsufficientFunds
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Should supply enough intrinsic gas
 | 
			
		||||
	if tx.GasLimit.Cmp(IntrinsicGas(tx)) < 0 {
 | 
			
		||||
	if tx.Gas().Cmp(IntrinsicGas(tx)) < 0 {
 | 
			
		||||
		return ErrIntrinsicGas
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -238,7 +236,7 @@ func (pool *TxPool) addTx(hash common.Hash, addr common.Address, tx *types.Trans
 | 
			
		||||
 | 
			
		||||
		// Increment the nonce on the pending state. This can only happen if
 | 
			
		||||
		// the nonce is +1 to the previous one.
 | 
			
		||||
		pool.pendingState.SetNonce(addr, tx.AccountNonce+1)
 | 
			
		||||
		pool.pendingState.SetNonce(addr, tx.Nonce()+1)
 | 
			
		||||
		// Notify the subscribers. This event is posted in a goroutine
 | 
			
		||||
		// because it's possible that somewhere during the post "Remove transaction"
 | 
			
		||||
		// gets called which will then wait for the global tx pool lock and deadlock.
 | 
			
		||||
@@ -341,7 +339,7 @@ func (pool *TxPool) checkQueue() {
 | 
			
		||||
		trueNonce := pool.currentState().GetNonce(address)
 | 
			
		||||
		addq := addq[:0]
 | 
			
		||||
		for hash, tx := range txs {
 | 
			
		||||
			if tx.AccountNonce < trueNonce {
 | 
			
		||||
			if tx.Nonce() < trueNonce {
 | 
			
		||||
				// Drop queued transactions whose nonce is lower than
 | 
			
		||||
				// the account nonce because they have been processed.
 | 
			
		||||
				delete(txs, hash)
 | 
			
		||||
@@ -362,8 +360,7 @@ func (pool *TxPool) checkQueue() {
 | 
			
		||||
				delete(pool.queue[address], e.hash)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if e.AccountNonce > guessedNonce {
 | 
			
		||||
			if e.Nonce() > guessedNonce {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			delete(txs, e.hash)
 | 
			
		||||
@@ -418,4 +415,4 @@ type txQueueEntry struct {
 | 
			
		||||
 | 
			
		||||
func (q txQueue) Len() int           { return len(q) }
 | 
			
		||||
func (q txQueue) Swap(i, j int)      { q[i], q[j] = q[j], q[i] }
 | 
			
		||||
func (q txQueue) Less(i, j int) bool { return q[i].AccountNonce < q[j].AccountNonce }
 | 
			
		||||
func (q txQueue) Less(i, j int) bool { return q[i].Nonce() < q[j].Nonce() }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,9 @@ import (
 | 
			
		||||
	"github.com/ethereum/go-ethereum/event"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func transaction() *types.Transaction {
 | 
			
		||||
	return types.NewTransactionMessage(common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(100), nil)
 | 
			
		||||
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)
 | 
			
		||||
	return tx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
 | 
			
		||||
@@ -29,43 +30,34 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
 | 
			
		||||
func TestInvalidTransactions(t *testing.T) {
 | 
			
		||||
	pool, key := setupTxPool()
 | 
			
		||||
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
	err := pool.Add(tx)
 | 
			
		||||
	if err != ErrNonExistentAccount {
 | 
			
		||||
	tx := transaction(0, big.NewInt(100), key)
 | 
			
		||||
	if err := pool.Add(tx); err != ErrNonExistentAccount {
 | 
			
		||||
		t.Error("expected", ErrNonExistentAccount)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	from, _ := tx.From()
 | 
			
		||||
	pool.currentState().AddBalance(from, big.NewInt(1))
 | 
			
		||||
	err = pool.Add(tx)
 | 
			
		||||
	if err != ErrInsufficientFunds {
 | 
			
		||||
	if err := pool.Add(tx); err != ErrInsufficientFunds {
 | 
			
		||||
		t.Error("expected", ErrInsufficientFunds)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice()))
 | 
			
		||||
	pool.currentState().AddBalance(from, balance)
 | 
			
		||||
	err = pool.Add(tx)
 | 
			
		||||
	if err != ErrIntrinsicGas {
 | 
			
		||||
	if err := pool.Add(tx); err != ErrIntrinsicGas {
 | 
			
		||||
		t.Error("expected", ErrIntrinsicGas, "got", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool.currentState().SetNonce(from, 1)
 | 
			
		||||
	pool.currentState().AddBalance(from, big.NewInt(0xffffffffffffff))
 | 
			
		||||
	tx.GasLimit = big.NewInt(100000)
 | 
			
		||||
	tx.Price = big.NewInt(1)
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
 | 
			
		||||
	err = pool.Add(tx)
 | 
			
		||||
	if err != ErrNonce {
 | 
			
		||||
	tx = transaction(0, big.NewInt(100000), key)
 | 
			
		||||
	if err := pool.Add(tx); err != ErrNonce {
 | 
			
		||||
		t.Error("expected", ErrNonce)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTransactionQueue(t *testing.T) {
 | 
			
		||||
	pool, key := setupTxPool()
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
	tx := transaction(0, big.NewInt(100), key)
 | 
			
		||||
	from, _ := tx.From()
 | 
			
		||||
	pool.currentState().AddBalance(from, big.NewInt(1))
 | 
			
		||||
	pool.queueTx(tx.Hash(), tx)
 | 
			
		||||
@@ -75,9 +67,7 @@ func TestTransactionQueue(t *testing.T) {
 | 
			
		||||
		t.Error("expected valid txs to be 1 is", len(pool.pending))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx = transaction()
 | 
			
		||||
	tx.SetNonce(1)
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
	tx = transaction(1, big.NewInt(100), key)
 | 
			
		||||
	from, _ = tx.From()
 | 
			
		||||
	pool.currentState().SetNonce(from, 2)
 | 
			
		||||
	pool.queueTx(tx.Hash(), tx)
 | 
			
		||||
@@ -91,12 +81,9 @@ func TestTransactionQueue(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool, key = setupTxPool()
 | 
			
		||||
	tx1, tx2, tx3 := transaction(), transaction(), transaction()
 | 
			
		||||
	tx2.SetNonce(10)
 | 
			
		||||
	tx3.SetNonce(11)
 | 
			
		||||
	tx1.SignECDSA(key)
 | 
			
		||||
	tx2.SignECDSA(key)
 | 
			
		||||
	tx3.SignECDSA(key)
 | 
			
		||||
	tx1 := transaction(0, big.NewInt(100), key)
 | 
			
		||||
	tx2 := transaction(10, big.NewInt(100), key)
 | 
			
		||||
	tx3 := transaction(11, big.NewInt(100), key)
 | 
			
		||||
	pool.queueTx(tx1.Hash(), tx1)
 | 
			
		||||
	pool.queueTx(tx2.Hash(), tx2)
 | 
			
		||||
	pool.queueTx(tx3.Hash(), tx3)
 | 
			
		||||
@@ -114,8 +101,7 @@ func TestTransactionQueue(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestRemoveTx(t *testing.T) {
 | 
			
		||||
	pool, key := setupTxPool()
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
	tx := transaction(0, big.NewInt(100), key)
 | 
			
		||||
	from, _ := tx.From()
 | 
			
		||||
	pool.currentState().AddBalance(from, big.NewInt(1))
 | 
			
		||||
	pool.queueTx(tx.Hash(), tx)
 | 
			
		||||
@@ -142,13 +128,10 @@ func TestRemoveTx(t *testing.T) {
 | 
			
		||||
func TestNegativeValue(t *testing.T) {
 | 
			
		||||
	pool, key := setupTxPool()
 | 
			
		||||
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.Value().Set(big.NewInt(-1))
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
	tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key)
 | 
			
		||||
	from, _ := tx.From()
 | 
			
		||||
	pool.currentState().AddBalance(from, big.NewInt(1))
 | 
			
		||||
	err := pool.Add(tx)
 | 
			
		||||
	if err != ErrNegativeValue {
 | 
			
		||||
	if err := pool.Add(tx); err != ErrNegativeValue {
 | 
			
		||||
		t.Error("expected", ErrNegativeValue, "got", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -165,20 +148,15 @@ func TestTransactionChainFork(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	resetState()
 | 
			
		||||
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.GasLimit = big.NewInt(100000)
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
 | 
			
		||||
	err := pool.add(tx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	tx := transaction(0, big.NewInt(100000), key)
 | 
			
		||||
	if err := pool.add(tx); err != nil {
 | 
			
		||||
		t.Error("didn't expect error", err)
 | 
			
		||||
	}
 | 
			
		||||
	pool.RemoveTransactions([]*types.Transaction{tx})
 | 
			
		||||
 | 
			
		||||
	// reset the pool's internal state
 | 
			
		||||
	resetState()
 | 
			
		||||
	err = pool.add(tx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if err := pool.add(tx); err != nil {
 | 
			
		||||
		t.Error("didn't expect error", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -195,24 +173,14 @@ func TestTransactionDoubleNonce(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	resetState()
 | 
			
		||||
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.GasLimit = big.NewInt(100000)
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
 | 
			
		||||
	err := pool.add(tx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	tx := transaction(0, big.NewInt(100000), key)
 | 
			
		||||
	tx2 := transaction(0, big.NewInt(1000000), key)
 | 
			
		||||
	if err := pool.add(tx); err != nil {
 | 
			
		||||
		t.Error("didn't expect error", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx2 := transaction()
 | 
			
		||||
	tx2.GasLimit = big.NewInt(1000000)
 | 
			
		||||
	tx2.SignECDSA(key)
 | 
			
		||||
 | 
			
		||||
	err = pool.add(tx2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if err := pool.add(tx2); err != nil {
 | 
			
		||||
		t.Error("didn't expect error", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(pool.pending) != 2 {
 | 
			
		||||
		t.Error("expected 2 pending txs. Got", len(pool.pending))
 | 
			
		||||
	}
 | 
			
		||||
@@ -222,20 +190,13 @@ func TestMissingNonce(t *testing.T) {
 | 
			
		||||
	pool, key := setupTxPool()
 | 
			
		||||
	addr := crypto.PubkeyToAddress(key.PublicKey)
 | 
			
		||||
	pool.currentState().AddBalance(addr, big.NewInt(100000000000000))
 | 
			
		||||
	tx := transaction()
 | 
			
		||||
	tx.AccountNonce = 1
 | 
			
		||||
	tx.GasLimit = big.NewInt(100000)
 | 
			
		||||
	tx.SignECDSA(key)
 | 
			
		||||
 | 
			
		||||
	err := pool.add(tx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	tx := transaction(1, big.NewInt(100000), key)
 | 
			
		||||
	if err := pool.add(tx); err != nil {
 | 
			
		||||
		t.Error("didn't expect error", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(pool.pending) != 0 {
 | 
			
		||||
		t.Error("expected 0 pending transactions, got", len(pool.pending))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(pool.queue[addr]) != 1 {
 | 
			
		||||
		t.Error("expected 1 queued transaction, got", len(pool.queue[addr]))
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@ import (
 | 
			
		||||
// from bcValidBlockTest.json, "SimpleTx"
 | 
			
		||||
func TestBlockEncoding(t *testing.T) {
 | 
			
		||||
	blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0")
 | 
			
		||||
 | 
			
		||||
	var block Block
 | 
			
		||||
	if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
 | 
			
		||||
		t.Fatal("decode error: ", err)
 | 
			
		||||
@@ -35,20 +34,10 @@ func TestBlockEncoding(t *testing.T) {
 | 
			
		||||
	check("Time", block.Time(), int64(1426516743))
 | 
			
		||||
	check("Size", block.Size(), common.StorageSize(len(blockEnc)))
 | 
			
		||||
 | 
			
		||||
	to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
 | 
			
		||||
	check("Transactions", block.Transactions(), Transactions{
 | 
			
		||||
		{
 | 
			
		||||
			Payload:      []byte{},
 | 
			
		||||
			Amount:       big.NewInt(10),
 | 
			
		||||
			Price:        big.NewInt(10),
 | 
			
		||||
			GasLimit:     big.NewInt(50000),
 | 
			
		||||
			AccountNonce: 0,
 | 
			
		||||
			V:            27,
 | 
			
		||||
			R:            common.String2Big("0x9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"),
 | 
			
		||||
			S:            common.String2Big("0x8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"),
 | 
			
		||||
			Recipient:    &to,
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
 | 
			
		||||
	tx1, _ = tx1.WithSignature(common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
 | 
			
		||||
	check("len(Transactions)", len(block.Transactions()), 1)
 | 
			
		||||
	check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
 | 
			
		||||
 | 
			
		||||
	ourBlockEnc, err := rlp.EncodeToBytes(&block)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/go-ethereum/common"
 | 
			
		||||
@@ -18,38 +19,59 @@ func IsContractAddr(addr []byte) bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Transaction struct {
 | 
			
		||||
	data txdata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type txdata struct {
 | 
			
		||||
	AccountNonce    uint64
 | 
			
		||||
	Price        *big.Int
 | 
			
		||||
	GasLimit     *big.Int
 | 
			
		||||
	Price, GasLimit *big.Int
 | 
			
		||||
	Recipient       *common.Address `rlp:"nil"` // nil means contract creation
 | 
			
		||||
	Amount          *big.Int
 | 
			
		||||
	Payload         []byte
 | 
			
		||||
	V            byte
 | 
			
		||||
	R, S         *big.Int
 | 
			
		||||
	V               byte     // signature
 | 
			
		||||
	R, S            *big.Int // signature
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewContractCreationTx(amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
 | 
			
		||||
	return &Transaction{
 | 
			
		||||
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:    amount,
 | 
			
		||||
		GasLimit:  gasLimit,
 | 
			
		||||
		Price:     gasPrice,
 | 
			
		||||
		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 NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.Int, data []byte) *Transaction {
 | 
			
		||||
	return &Transaction{
 | 
			
		||||
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,
 | 
			
		||||
		Amount:    amount,
 | 
			
		||||
		GasLimit:  gasAmount,
 | 
			
		||||
		Price:     gasPrice,
 | 
			
		||||
		Payload:      data,
 | 
			
		||||
		Amount:       new(big.Int),
 | 
			
		||||
		GasLimit:     new(big.Int),
 | 
			
		||||
		Price:        new(big.Int),
 | 
			
		||||
		R:            new(big.Int),
 | 
			
		||||
		S:            new(big.Int),
 | 
			
		||||
	}
 | 
			
		||||
	if amount != nil {
 | 
			
		||||
		d.Amount.Set(amount)
 | 
			
		||||
	}
 | 
			
		||||
	if gasLimit != nil {
 | 
			
		||||
		d.GasLimit.Set(gasLimit)
 | 
			
		||||
	}
 | 
			
		||||
	if gasPrice != nil {
 | 
			
		||||
		d.Price.Set(gasPrice)
 | 
			
		||||
	}
 | 
			
		||||
	return &Transaction{data: d}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTransactionFromBytes(data []byte) *Transaction {
 | 
			
		||||
@@ -61,112 +83,110 @@ func NewTransactionFromBytes(data []byte) *Transaction {
 | 
			
		||||
	return tx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
 | 
			
		||||
	return rlp.Encode(w, &tx.data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
 | 
			
		||||
	return s.Decode(&tx.data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) Data() []byte       { return common.CopyBytes(tx.data.Payload) }
 | 
			
		||||
func (tx *Transaction) Gas() *big.Int      { return new(big.Int).Set(tx.data.GasLimit) }
 | 
			
		||||
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
 | 
			
		||||
func (tx *Transaction) Value() *big.Int    { return new(big.Int).Set(tx.data.Amount) }
 | 
			
		||||
func (tx *Transaction) Nonce() uint64      { return tx.data.AccountNonce }
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) To() *common.Address {
 | 
			
		||||
	if tx.data.Recipient == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		to := *tx.data.Recipient
 | 
			
		||||
		return &to
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) Hash() common.Hash {
 | 
			
		||||
	return rlpHash([]interface{}{
 | 
			
		||||
		tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload,
 | 
			
		||||
	v := rlpHash([]interface{}{
 | 
			
		||||
		tx.data.AccountNonce,
 | 
			
		||||
		tx.data.Price,
 | 
			
		||||
		tx.data.GasLimit,
 | 
			
		||||
		tx.data.Recipient,
 | 
			
		||||
		tx.data.Amount,
 | 
			
		||||
		tx.data.Payload,
 | 
			
		||||
	})
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Size returns the encoded RLP size of tx.
 | 
			
		||||
func (self *Transaction) Size() common.StorageSize {
 | 
			
		||||
	c := writeCounter(0)
 | 
			
		||||
	rlp.Encode(&c, self)
 | 
			
		||||
	return common.StorageSize(c)
 | 
			
		||||
func (tx *Transaction) Size() common.StorageSize {
 | 
			
		||||
	v, _, _ := rlp.EncodeToReader(&tx.data)
 | 
			
		||||
	return common.StorageSize(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) Data() []byte {
 | 
			
		||||
	return self.Payload
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) Gas() *big.Int {
 | 
			
		||||
	return self.GasLimit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) GasPrice() *big.Int {
 | 
			
		||||
	return self.Price
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) Value() *big.Int {
 | 
			
		||||
	return self.Amount
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) Nonce() uint64 {
 | 
			
		||||
	return self.AccountNonce
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) SetNonce(AccountNonce uint64) {
 | 
			
		||||
	self.AccountNonce = AccountNonce
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *Transaction) From() (common.Address, error) {
 | 
			
		||||
	pubkey, err := self.PublicKey()
 | 
			
		||||
func (tx *Transaction) From() (common.Address, error) {
 | 
			
		||||
	pubkey, err := tx.PublicKey()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return common.Address{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var addr common.Address
 | 
			
		||||
	copy(addr[:], crypto.Sha3(pubkey[1:])[12:])
 | 
			
		||||
	return addr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// To returns the recipient of the transaction.
 | 
			
		||||
// If transaction is a contract creation (with no recipient address)
 | 
			
		||||
// To returns nil.
 | 
			
		||||
func (tx *Transaction) To() *common.Address {
 | 
			
		||||
	return tx.Recipient
 | 
			
		||||
// Cost returns amount + gasprice * gaslimit.
 | 
			
		||||
func (tx *Transaction) Cost() *big.Int {
 | 
			
		||||
	total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit)
 | 
			
		||||
	total.Add(total, tx.data.Amount)
 | 
			
		||||
	return total
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) GetSignatureValues() (v byte, r []byte, s []byte) {
 | 
			
		||||
	v = byte(tx.V)
 | 
			
		||||
	r = common.LeftPadBytes(tx.R.Bytes(), 32)
 | 
			
		||||
	s = common.LeftPadBytes(tx.S.Bytes(), 32)
 | 
			
		||||
	return
 | 
			
		||||
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() ([]byte, error) {
 | 
			
		||||
	if !crypto.ValidateSignatureValues(tx.V, tx.R, tx.S) {
 | 
			
		||||
	if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S) {
 | 
			
		||||
		return nil, errors.New("invalid v, r, s values")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hash := tx.Hash()
 | 
			
		||||
	v, r, s := tx.GetSignatureValues()
 | 
			
		||||
	sig := append(r, s...)
 | 
			
		||||
	sig = append(sig, v-27)
 | 
			
		||||
	// 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
 | 
			
		||||
 | 
			
		||||
	p, err := crypto.SigToPub(hash[:], sig)
 | 
			
		||||
	// recover the public key from the signature
 | 
			
		||||
	hash := tx.Hash()
 | 
			
		||||
	pub, err := crypto.Ecrecover(hash[:], sig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.V(logger.Error).Infof("Could not get pubkey from signature: ", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pubkey := crypto.FromECDSAPub(p)
 | 
			
		||||
	if len(pubkey) == 0 || pubkey[0] != 4 {
 | 
			
		||||
	if len(pub) == 0 || pub[0] != 4 {
 | 
			
		||||
		return nil, errors.New("invalid public key")
 | 
			
		||||
	}
 | 
			
		||||
	return pubkey, nil
 | 
			
		||||
	return pub, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) SetSignatureValues(sig []byte) error {
 | 
			
		||||
	tx.R = common.Bytes2Big(sig[:32])
 | 
			
		||||
	tx.S = common.Bytes2Big(sig[32:64])
 | 
			
		||||
	tx.V = sig[64] + 27
 | 
			
		||||
	return nil
 | 
			
		||||
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] + 27
 | 
			
		||||
	return cpy, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) error {
 | 
			
		||||
func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) (*Transaction, error) {
 | 
			
		||||
	h := tx.Hash()
 | 
			
		||||
	sig, err := crypto.Sign(h[:], prv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tx.SetSignatureValues(sig)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: remove
 | 
			
		||||
func (tx *Transaction) RlpData() interface{} {
 | 
			
		||||
	data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
 | 
			
		||||
	return append(data, tx.V, tx.R.Bytes(), tx.S.Bytes())
 | 
			
		||||
	return tx.WithSignature(sig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tx *Transaction) String() string {
 | 
			
		||||
@@ -176,12 +196,12 @@ func (tx *Transaction) String() string {
 | 
			
		||||
	} else {
 | 
			
		||||
		from = fmt.Sprintf("%x", f[:])
 | 
			
		||||
	}
 | 
			
		||||
	if t := tx.To(); t == nil {
 | 
			
		||||
	if tx.data.Recipient == nil {
 | 
			
		||||
		to = "[contract creation]"
 | 
			
		||||
	} else {
 | 
			
		||||
		to = fmt.Sprintf("%x", t[:])
 | 
			
		||||
		to = fmt.Sprintf("%x", tx.data.Recipient[:])
 | 
			
		||||
	}
 | 
			
		||||
	enc, _ := rlp.EncodeToBytes(tx)
 | 
			
		||||
	enc, _ := rlp.EncodeToBytes(&tx.data)
 | 
			
		||||
	return fmt.Sprintf(`
 | 
			
		||||
	TX(%x)
 | 
			
		||||
	Contract: %v
 | 
			
		||||
@@ -198,36 +218,24 @@ func (tx *Transaction) String() string {
 | 
			
		||||
	Hex:      %x
 | 
			
		||||
`,
 | 
			
		||||
		tx.Hash(),
 | 
			
		||||
		len(tx.Recipient) == 0,
 | 
			
		||||
		len(tx.data.Recipient) == 0,
 | 
			
		||||
		from,
 | 
			
		||||
		to,
 | 
			
		||||
		tx.AccountNonce,
 | 
			
		||||
		tx.Price,
 | 
			
		||||
		tx.GasLimit,
 | 
			
		||||
		tx.Amount,
 | 
			
		||||
		tx.Payload,
 | 
			
		||||
		tx.V,
 | 
			
		||||
		tx.R,
 | 
			
		||||
		tx.S,
 | 
			
		||||
		tx.data.AccountNonce,
 | 
			
		||||
		tx.data.Price,
 | 
			
		||||
		tx.data.GasLimit,
 | 
			
		||||
		tx.data.Amount,
 | 
			
		||||
		tx.data.Payload,
 | 
			
		||||
		tx.data.V,
 | 
			
		||||
		tx.data.R,
 | 
			
		||||
		tx.data.S,
 | 
			
		||||
		enc,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Transaction slice type for basic sorting
 | 
			
		||||
// Transaction slice type for basic sorting.
 | 
			
		||||
type Transactions []*Transaction
 | 
			
		||||
 | 
			
		||||
// TODO: remove
 | 
			
		||||
func (self Transactions) RlpData() interface{} {
 | 
			
		||||
	// Marshal the transactions of this block
 | 
			
		||||
	enc := make([]interface{}, len(self))
 | 
			
		||||
	for i, tx := range self {
 | 
			
		||||
		// Cast it to a string (safe)
 | 
			
		||||
		enc[i] = tx.RlpData()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return enc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s Transactions) Len() int      { return len(s) }
 | 
			
		||||
func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 | 
			
		||||
 | 
			
		||||
@@ -239,5 +247,5 @@ func (s Transactions) GetRlp(i int) []byte {
 | 
			
		||||
type TxByNonce struct{ Transactions }
 | 
			
		||||
 | 
			
		||||
func (s TxByNonce) Less(i, j int) bool {
 | 
			
		||||
	return s.Transactions[i].AccountNonce < s.Transactions[j].AccountNonce
 | 
			
		||||
	return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,40 +15,35 @@ import (
 | 
			
		||||
// at github.com/ethereum/tests.
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	emptyTx = NewTransactionMessage(
 | 
			
		||||
	emptyTx = NewTransaction(
 | 
			
		||||
		0,
 | 
			
		||||
		common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
 | 
			
		||||
		big.NewInt(0), big.NewInt(0), big.NewInt(0),
 | 
			
		||||
		nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	rightvrsRecipient = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b")
 | 
			
		||||
	rightvrsTx        = &Transaction{
 | 
			
		||||
		Recipient:    &rightvrsRecipient,
 | 
			
		||||
		AccountNonce: 3,
 | 
			
		||||
		Price:        big.NewInt(1),
 | 
			
		||||
		GasLimit:     big.NewInt(2000),
 | 
			
		||||
		Amount:       big.NewInt(10),
 | 
			
		||||
		Payload:      common.FromHex("5544"),
 | 
			
		||||
		V:            28,
 | 
			
		||||
		R:            common.String2Big("0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a"),
 | 
			
		||||
		S:            common.String2Big("0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"),
 | 
			
		||||
	}
 | 
			
		||||
	rightvrsTx, _ = NewTransaction(
 | 
			
		||||
		3,
 | 
			
		||||
		common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
 | 
			
		||||
		big.NewInt(10),
 | 
			
		||||
		big.NewInt(2000),
 | 
			
		||||
		big.NewInt(1),
 | 
			
		||||
		common.FromHex("5544"),
 | 
			
		||||
	).WithSignature(
 | 
			
		||||
		common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
 | 
			
		||||
	)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTransactionHash(t *testing.T) {
 | 
			
		||||
	// "EmptyTransaction"
 | 
			
		||||
	if emptyTx.Hash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
 | 
			
		||||
		t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// "RightVRSTest"
 | 
			
		||||
	if rightvrsTx.Hash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
 | 
			
		||||
		t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTransactionEncode(t *testing.T) {
 | 
			
		||||
	// "RightVRSTest"
 | 
			
		||||
	txb, err := rlp.EncodeToBytes(rightvrsTx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("encode error: %v", err)
 | 
			
		||||
@@ -72,19 +67,16 @@ func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
 | 
			
		||||
 | 
			
		||||
func TestRecipientEmpty(t *testing.T) {
 | 
			
		||||
	_, addr := defaultTestKey()
 | 
			
		||||
 | 
			
		||||
	tx, err := decodeTx(common.Hex2Bytes("f8498080808080011ca09b16de9d5bdee2cf56c28d16275a4da68cd30273e2525f3959f5d62557489921a0372ebd8fb3345f7db7b5a86d42e24d36e983e259b0664ceb8c227ec9af572f3d"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
		t.FailNow()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	from, err := tx.From()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
		t.FailNow()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if addr != from {
 | 
			
		||||
		t.Error("derived address doesn't match")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -234,7 +234,7 @@ func (pool *fakeTxPool) GetTransactions() types.Transactions {
 | 
			
		||||
 | 
			
		||||
func newtx(from *crypto.Key, nonce uint64, datasize int) *types.Transaction {
 | 
			
		||||
	data := make([]byte, datasize)
 | 
			
		||||
	tx := types.NewTransactionMessage(common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), data)
 | 
			
		||||
	tx.SetNonce(nonce)
 | 
			
		||||
	tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), data)
 | 
			
		||||
	tx, _ = tx.SignECDSA(from.PrivateKey)
 | 
			
		||||
	return tx
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -152,54 +152,53 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedData := mustConvertBytes(txTest.Transaction.Data)
 | 
			
		||||
	if !bytes.Equal(expectedData, decodedTx.Payload) {
 | 
			
		||||
		return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Payload)
 | 
			
		||||
	if !bytes.Equal(expectedData, decodedTx.Data()) {
 | 
			
		||||
		return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Data())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedGasLimit := mustConvertBigInt(txTest.Transaction.GasLimit, 16)
 | 
			
		||||
	if expectedGasLimit.Cmp(decodedTx.GasLimit) != 0 {
 | 
			
		||||
		return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.GasLimit)
 | 
			
		||||
	if expectedGasLimit.Cmp(decodedTx.Gas()) != 0 {
 | 
			
		||||
		return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.Gas())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedGasPrice := mustConvertBigInt(txTest.Transaction.GasPrice, 16)
 | 
			
		||||
	if expectedGasPrice.Cmp(decodedTx.Price) != 0 {
 | 
			
		||||
		return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.Price)
 | 
			
		||||
	if expectedGasPrice.Cmp(decodedTx.GasPrice()) != 0 {
 | 
			
		||||
		return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.GasPrice())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedNonce := mustConvertUint(txTest.Transaction.Nonce, 16)
 | 
			
		||||
	if expectedNonce != decodedTx.AccountNonce {
 | 
			
		||||
		return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.AccountNonce)
 | 
			
		||||
	if expectedNonce != decodedTx.Nonce() {
 | 
			
		||||
		return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedR := common.Bytes2Big(mustConvertBytes(txTest.Transaction.R))
 | 
			
		||||
	if expectedR.Cmp(decodedTx.R) != 0 {
 | 
			
		||||
		return fmt.Errorf("R mismatch: %v %v", expectedR, decodedTx.R)
 | 
			
		||||
	v, r, s := decodedTx.SignatureValues()
 | 
			
		||||
	expectedR := mustConvertBigInt(txTest.Transaction.R, 16)
 | 
			
		||||
	if r.Cmp(expectedR) != 0 {
 | 
			
		||||
		return fmt.Errorf("R mismatch: %v %v", expectedR, r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedS := common.Bytes2Big(mustConvertBytes(txTest.Transaction.S))
 | 
			
		||||
	if expectedS.Cmp(decodedTx.S) != 0 {
 | 
			
		||||
		return fmt.Errorf("S mismatch: %v %v", expectedS, decodedTx.S)
 | 
			
		||||
	expectedS := mustConvertBigInt(txTest.Transaction.S, 16)
 | 
			
		||||
	if s.Cmp(expectedS) != 0 {
 | 
			
		||||
		return fmt.Errorf("S mismatch: %v %v", expectedS, s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedV := mustConvertUint(txTest.Transaction.V, 16)
 | 
			
		||||
	if expectedV != uint64(decodedTx.V) {
 | 
			
		||||
		return fmt.Errorf("V mismatch: %v %v", expectedV, uint64(decodedTx.V))
 | 
			
		||||
	if uint64(v) != expectedV {
 | 
			
		||||
		return fmt.Errorf("V mismatch: %v %v", expectedV, v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedTo := mustConvertAddress(txTest.Transaction.To)
 | 
			
		||||
	if decodedTx.Recipient == nil {
 | 
			
		||||
	if decodedTx.To() == nil {
 | 
			
		||||
		if expectedTo != common.BytesToAddress([]byte{}) { // "empty" or "zero" address
 | 
			
		||||
			return fmt.Errorf("To mismatch when recipient is nil (contract creation): %v", expectedTo)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if expectedTo != *decodedTx.Recipient {
 | 
			
		||||
			return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.Recipient)
 | 
			
		||||
		if expectedTo != *decodedTx.To() {
 | 
			
		||||
			return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.To())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedValue := mustConvertBigInt(txTest.Transaction.Value, 16)
 | 
			
		||||
	if expectedValue.Cmp(decodedTx.Amount) != 0 {
 | 
			
		||||
		return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Amount)
 | 
			
		||||
	if expectedValue.Cmp(decodedTx.Value()) != 0 {
 | 
			
		||||
		return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Value())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								xeth/xeth.go
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								xeth/xeth.go
									
									
									
									
									
								
							@@ -946,51 +946,45 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
 | 
			
		||||
 | 
			
		||||
	// TODO: align default values to have the same type, e.g. not depend on
 | 
			
		||||
	// common.Value conversions later on
 | 
			
		||||
 | 
			
		||||
	var tx *types.Transaction
 | 
			
		||||
	if contractCreation {
 | 
			
		||||
		tx = types.NewContractCreationTx(value, gas, price, data)
 | 
			
		||||
	} else {
 | 
			
		||||
		tx = types.NewTransactionMessage(to, value, gas, price, data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state := self.backend.TxPool().State()
 | 
			
		||||
 | 
			
		||||
	var nonce uint64
 | 
			
		||||
	if len(nonceStr) != 0 {
 | 
			
		||||
		nonce = common.Big(nonceStr).Uint64()
 | 
			
		||||
	} else {
 | 
			
		||||
		state := self.backend.TxPool().State()
 | 
			
		||||
		nonce = state.GetNonce(from)
 | 
			
		||||
	}
 | 
			
		||||
	tx.SetNonce(nonce)
 | 
			
		||||
	var tx *types.Transaction
 | 
			
		||||
	if contractCreation {
 | 
			
		||||
		tx = types.NewContractCreation(nonce, value, gas, price, data)
 | 
			
		||||
	} else {
 | 
			
		||||
		tx = types.NewTransaction(nonce, to, value, gas, price, data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := self.sign(tx, from, false); err != nil {
 | 
			
		||||
	signed, err := self.sign(tx, from, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	if err := self.backend.TxPool().Add(tx); err != nil {
 | 
			
		||||
	if err = self.backend.TxPool().Add(signed); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	//state.SetNonce(from, nonce+1)
 | 
			
		||||
 | 
			
		||||
	if contractCreation {
 | 
			
		||||
		addr := core.AddressFromMessage(tx)
 | 
			
		||||
		glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr)
 | 
			
		||||
 | 
			
		||||
		return core.AddressFromMessage(tx).Hex(), nil
 | 
			
		||||
		return addr.Hex(), nil
 | 
			
		||||
	} else {
 | 
			
		||||
		glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To())
 | 
			
		||||
	}
 | 
			
		||||
	return tx.Hash().Hex(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) error {
 | 
			
		||||
func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) (*types.Transaction, error) {
 | 
			
		||||
	hash := tx.Hash()
 | 
			
		||||
	sig, err := self.doSign(from, hash, didUnlock)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return tx, err
 | 
			
		||||
	}
 | 
			
		||||
	tx.SetSignatureValues(sig)
 | 
			
		||||
	return nil
 | 
			
		||||
	return tx.WithSignature(sig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// callmsg is the message type used for call transations.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user