From 4dca5d4db7fc2c1fac5a2e24dcc99b15573f0188 Mon Sep 17 00:00:00 2001
From: Jeffrey Wilcke <jeffrey@ethereum.org>
Date: Wed, 2 Nov 2016 13:44:13 +0100
Subject: [PATCH] core/types, params: EIP#155

---
 accounts/abi/bind/auth.go               |   6 +-
 accounts/abi/bind/backends/simulated.go |  19 +-
 accounts/abi/bind/base.go               |   4 +-
 accounts/abi/bind/util_test.go          |   2 +-
 cmd/utils/flags.go                      |   4 +
 common/registrar/ethreg/api.go          |  28 +-
 console/console_test.go                 |   2 +-
 core/bench_test.go                      |   4 +-
 core/blockchain.go                      |  13 +-
 core/blockchain_test.go                 | 128 ++++++++-
 core/chain_makers_test.go               |   7 +-
 core/state_processor.go                 |  19 +-
 core/state_transition.go                |  39 +--
 core/tx_pool.go                         |  18 +-
 core/tx_pool_test.go                    |  51 ++--
 core/types/block_test.go                |   7 +-
 core/types/json_test.go                 |   5 +-
 core/types/transaction.go               | 260 +++++++++++-------
 core/types/transaction_signing.go       | 340 ++++++++++++++++++++++++
 core/types/transaction_signing_test.go  | 116 ++++++++
 core/types/transaction_test.go          |  28 +-
 core/vm/jit_test.go                     |   2 +-
 core/vm/runtime/runtime.go              |   2 +-
 core/vm_env.go                          |   2 +-
 eth/api.go                              |  12 +-
 eth/api_backend.go                      |  12 +-
 eth/downloader/downloader_test.go       |   3 +-
 eth/fetcher/fetcher_test.go             |   3 +-
 eth/handler_test.go                     |  14 +-
 eth/helper_test.go                      |   4 +-
 ethclient/ethclient.go                  |   8 +-
 internal/ethapi/api.go                  |  86 +++---
 internal/ethapi/backend.go              |   4 +
 les/api_backend.go                      |  11 +-
 les/helper_test.go                      |  16 +-
 les/odr_test.go                         |  59 +---
 light/odr_test.go                       |  73 +----
 light/txpool.go                         |  16 +-
 light/txpool_test.go                    |   2 +-
 light/vm_env.go                         |   2 +-
 miner/worker.go                         |  19 +-
 params/config.go                        |  36 ++-
 tests/state_test_util.go                |   3 +-
 tests/transaction_test_util.go          |  13 +-
 tests/util.go                           |  23 --
 tests/vm_test_util.go                   |   7 +-
 46 files changed, 1068 insertions(+), 464 deletions(-)
 create mode 100644 core/types/transaction_signing.go
 create mode 100644 core/types/transaction_signing_test.go

diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go
index cd6adc7462a9..a20852fca025 100644
--- a/accounts/abi/bind/auth.go
+++ b/accounts/abi/bind/auth.go
@@ -48,15 +48,15 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
 	keyAddr := crypto.PubkeyToAddress(key.PublicKey)
 	return &TransactOpts{
 		From: keyAddr,
-		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
+		Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) {
 			if address != keyAddr {
 				return nil, errors.New("not authorized to sign this account")
 			}
-			signature, err := crypto.SignEthereum(tx.SigHash().Bytes(), key)
+			signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key)
 			if err != nil {
 				return nil, err
 			}
-			return tx.WithSignature(signature)
+			return tx.WithSignature(signer, signature)
 		},
 	}
 }
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index f750a1fbdb89..00a8cd3e92e3 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -237,7 +237,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 	b.mu.Lock()
 	defer b.mu.Unlock()
 
-	sender, err := tx.From()
+	sender, err := types.Sender(types.HomesteadSigner{}, tx)
 	if err != nil {
 		panic(fmt.Errorf("invalid transaction: %v", err))
 	}
@@ -262,12 +262,11 @@ type callmsg struct {
 	ethereum.CallMsg
 }
 
-func (m callmsg) From() (common.Address, error)         { return m.CallMsg.From, nil }
-func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil }
-func (m callmsg) Nonce() uint64                         { return 0 }
-func (m callmsg) CheckNonce() bool                      { return false }
-func (m callmsg) To() *common.Address                   { return m.CallMsg.To }
-func (m callmsg) GasPrice() *big.Int                    { return m.CallMsg.GasPrice }
-func (m callmsg) Gas() *big.Int                         { return m.CallMsg.Gas }
-func (m callmsg) Value() *big.Int                       { return m.CallMsg.Value }
-func (m callmsg) Data() []byte                          { return m.CallMsg.Data }
+func (m callmsg) From() common.Address { return m.CallMsg.From }
+func (m callmsg) Nonce() uint64        { return 0 }
+func (m callmsg) CheckNonce() bool     { return false }
+func (m callmsg) To() *common.Address  { return m.CallMsg.To }
+func (m callmsg) GasPrice() *big.Int   { return m.CallMsg.GasPrice }
+func (m callmsg) Gas() *big.Int        { return m.CallMsg.Gas }
+func (m callmsg) Value() *big.Int      { return m.CallMsg.Value }
+func (m callmsg) Data() []byte         { return m.CallMsg.Data }
diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go
index b032ef72d96b..7df02e83f3e3 100644
--- a/accounts/abi/bind/base.go
+++ b/accounts/abi/bind/base.go
@@ -31,7 +31,7 @@ import (
 
 // SignerFn is a signer function callback when a contract requires a method to
 // sign the transaction before submission.
-type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error)
+type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error)
 
 // CallOpts is the collection of options to fine tune a contract call request.
 type CallOpts struct {
@@ -214,7 +214,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
 	if opts.Signer == nil {
 		return nil, errors.New("no signer to authorize the transaction with")
 	}
-	signedTx, err := opts.Signer(opts.From, rawTx)
+	signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx)
 	if err != nil {
 		return nil, err
 	}
diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go
index 192fa4f4cf73..d3ed02575a97 100644
--- a/accounts/abi/bind/util_test.go
+++ b/accounts/abi/bind/util_test.go
@@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
 
 		// Create the transaction.
 		tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
-		tx, _ = tx.SignECDSA(testKey)
+		tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey)
 
 		// Wait for it to get mined in the background.
 		var (
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 641ff6d40495..52b78a5c3ac2 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -825,6 +825,10 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainCon
 			Fatalf("Could not make chain configuration: %v", err)
 		}
 	}
+	// set chain id in case it's zero.
+	if config.ChainId == nil {
+		config.ChainId = new(big.Int)
+	}
 	// Check whether we are allowed to set default config params or not:
 	//  - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
 	//  - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
diff --git a/common/registrar/ethreg/api.go b/common/registrar/ethreg/api.go
index bbc34f6ac8e9..a3c48345ef58 100644
--- a/common/registrar/ethreg/api.go
+++ b/common/registrar/ethreg/api.go
@@ -174,25 +174,20 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr
 
 	from.SetBalance(common.MaxBig)
 
-	msg := callmsg{
-		from:     from,
-		gas:      common.Big(gasStr),
-		gasPrice: common.Big(gasPriceStr),
-		value:    common.Big(valueStr),
-		data:     common.FromHex(dataStr),
-	}
+	var to *common.Address
 	if len(toStr) > 0 {
 		addr := common.HexToAddress(toStr)
-		msg.to = &addr
+		to = &addr
 	}
-
-	if msg.gas.Cmp(big.NewInt(0)) == 0 {
-		msg.gas = big.NewInt(50000000)
+	gas := common.Big(gasStr)
+	if gas.BitLen() == 0 {
+		gas = big.NewInt(50000000)
 	}
-
-	if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
-		msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
+	gasPrice := common.Big(gasPriceStr)
+	if gasPrice.BitLen() == 0 {
+		gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
 	}
+	msg := types.NewMessage(from.Address(), to, 0, common.Big(valueStr), gas, gasPrice, common.FromHex(dataStr))
 
 	header := be.bc.CurrentBlock().Header()
 	vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
@@ -258,11 +253,12 @@ func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasSt
 		tx = types.NewTransaction(nonce, to, value, gas, price, data)
 	}
 
-	signature, err := be.am.SignEthereum(from, tx.SigHash().Bytes())
+	sigHash := (types.HomesteadSigner{}).Hash(tx)
+	signature, err := be.am.SignEthereum(from, sigHash.Bytes())
 	if err != nil {
 		return "", err
 	}
-	signedTx, err := tx.WithSignature(signature)
+	signedTx, err := tx.WithSignature(types.HomesteadSigner{}, signature)
 	if err != nil {
 		return "", err
 	}
diff --git a/console/console_test.go b/console/console_test.go
index 77dcc198cf6b..d5010b907d57 100644
--- a/console/console_test.go
+++ b/console/console_test.go
@@ -97,7 +97,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
 		t.Fatalf("failed to create node: %v", err)
 	}
 	ethConf := &eth.Config{
-		ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int)},
+		ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
 		Etherbase:   common.HexToAddress(testAddress),
 		PowTest:     true,
 	}
diff --git a/core/bench_test.go b/core/bench_test.go
index 8fe4d41de784..a208ea25045e 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -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
 		}
diff --git a/core/blockchain.go b/core/blockchain.go
index 8b93da60b632..bbcff3b92d61 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -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)
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 968cb25acd1a..dae857f01160 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -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  = &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
+		mux     event.TypeMux
+	)
+
+	blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux)
+	blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
+		var (
+			tx      *types.Transaction
+			err     error
+			basicTx = func(signer types.Signer) (*types.Transaction, error) {
+				return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
+			}
+		)
+		switch i {
+		case 0:
+			tx, err = basicTx(types.HomesteadSigner{})
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+		case 2:
+			tx, err = basicTx(types.HomesteadSigner{})
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+
+			tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+		case 3:
+			tx, err = basicTx(types.HomesteadSigner{})
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+
+			tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+		}
+	})
+
+	if _, err := blockchain.InsertChain(blocks); err != nil {
+		t.Fatal(err)
+	}
+	block := blockchain.GetBlockByNumber(1)
+	if block.Transactions()[0].Protected() {
+		t.Error("Expected block[0].txs[0] to not be replay protected")
+	}
+
+	block = blockchain.GetBlockByNumber(3)
+	if block.Transactions()[0].Protected() {
+		t.Error("Expected block[3].txs[0] to not be replay protected")
+	}
+	if !block.Transactions()[1].Protected() {
+		t.Error("Expected block[3].txs[1] to be replay protected")
+	}
+	if _, err := blockchain.InsertChain(blocks[4:]); err != nil {
+		t.Fatal(err)
+	}
+
+	// generate an invalid chain id transaction
+	config = &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
+	blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
+		var (
+			tx      *types.Transaction
+			err     error
+			basicTx = func(signer types.Signer) (*types.Transaction, error) {
+				return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
+			}
+		)
+		switch i {
+		case 0:
+			tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
+			if err != nil {
+				t.Fatal(err)
+			}
+			block.AddTx(tx)
+		}
+	})
+	errExp := "Invalid transaction chain id. Current chain id: 1 tx chain id: 2"
+	_, err := blockchain.InsertChain(blocks)
+	if err == nil {
+		t.Error("expected transaction chain id error")
+	} else if err.Error() != errExp {
+		t.Error("expected:", errExp, "got:", err)
+	}
+}
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index b297e671eb5e..487cd6e186db 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -39,6 +39,7 @@ func ExampleGenerateChain() {
 		addr2   = crypto.PubkeyToAddress(key2.PublicKey)
 		addr3   = crypto.PubkeyToAddress(key3.PublicKey)
 		db, _   = ethdb.NewMemDatabase()
+		signer  = types.HomesteadSigner{}
 	)
 
 	chainConfig := &params.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:
diff --git a/core/state_processor.go b/core/state_processor.go
index 9d78400627ad..46c5db0ee7ef 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -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())
diff --git a/core/state_transition.go b/core/state_transition.go
index 2b9d1c6d1d8d..8abe17b0a25f 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -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)
 
diff --git a/core/tx_pool.go b/core/tx_pool.go
index f1e5f0bddfc7..edcbc21ebfcc 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -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)
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index dbe6fa635005..009d19886931 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -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))
 
diff --git a/core/types/block_test.go b/core/types/block_test.go
index ac7f17c0d898..b95bddcfce25 100644
--- a/core/types/block_test.go
+++ b/core/types/block_test.go
@@ -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())
 
diff --git a/core/types/json_test.go b/core/types/json_test.go
index a028b5d08c9b..d80cda68b242 100644
--- a/core/types/json_test.go
+++ b/core/types/json_test.go
@@ -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)
 		}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index ceea4f9592db..972a36706fc5 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -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 NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
+	return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
+}
+
 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),
-	}}
+	return newTransaction(nonce, nil, 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 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)
-}
-
-// 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)
-}
+	if tx.signer == nil {
+		return common.Address{}, errNoSigner
+	}
 
-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,68 +303,70 @@ func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
 	return addr, nil
 }
 
-// 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
-}
-
 // 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) 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
 }
 
-func (tx *Transaction) publicKey(homestead bool) ([]byte, error) {
-	if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S, homestead) {
-		return nil, ErrInvalidSig
+*/
+
+// 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,
 	}
 
-	// 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
+	var err error
+	msg.from, err = Sender(s, tx)
+	return msg, err
+}
 
-	// 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
+// 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(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) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
+	return signer.WithSignature(tx, sig)
 }
 
-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)
+// 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) 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 }
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
new file mode 100644
index 000000000000..48209e2d8e54
--- /dev/null
+++ b/core/types/transaction_signing.go
@@ -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))
+}
diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go
new file mode 100644
index 000000000000..89c590262949
--- /dev/null
+++ b/core/types/transaction_signing_test.go
@@ -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)
+		}
+
+	}
+}
diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go
index 98a78d221ebf..ca105566adc1 100644
--- a/core/types/transaction_test.go
+++ b/core/types/transaction_test.go
@@ -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())
 			}
diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go
index f9c0e8fa2eb6..6f7ba9250a8f 100644
--- a/core/vm/jit_test.go
+++ b/core/vm/jit_test.go
@@ -174,7 +174,7 @@ func NewEnv(config *Config) *Env {
 }
 
 func (self *Env) ChainConfig() *params.ChainConfig {
-	return &params.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{} }
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index f2d86a324718..c57747edcd28 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -57,7 +57,7 @@ type Config struct {
 // sets defaults on the config
 func setDefaults(cfg *Config) {
 	if cfg.ChainConfig == nil {
-		cfg.ChainConfig = &params.ChainConfig{new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int)}
+		cfg.ChainConfig = &params.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 {
diff --git a/core/vm_env.go b/core/vm_env.go
index 43e4d2fd6fc8..43637bd13225 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -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 }
diff --git a/eth/api.go b/eth/api.go
index 7932bbcb6dc1..b3185c392628 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -506,21 +506,15 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
 	if err != nil {
 		return nil, err
 	}
+
+	signer := types.MakeSigner(api.config, block.Number())
 	// Mutate the state and trace the selected transaction
 	for idx, tx := range block.Transactions() {
 		// Assemble the transaction call message
-		from, err := tx.FromFrontier()
+		msg, err := tx.AsMessage(signer)
 		if err != nil {
 			return nil, fmt.Errorf("sender retrieval failed: %v", err)
 		}
-		msg := callmsg{
-			addr:     from,
-			to:       tx.To(),
-			gas:      tx.Gas(),
-			gasPrice: tx.GasPrice(),
-			value:    tx.Value(),
-			data:     tx.Data(),
-		}
 		// Mutate the state if we haven't reached the tracing transaction yet
 		if uint64(idx) < txIndex {
 			vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})
diff --git a/eth/api_backend.go b/eth/api_backend.go
index f17ad6a15fba..0925132ef067 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -30,6 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
+	"github.com/ethereum/go-ethereum/params"
 	rpc "github.com/ethereum/go-ethereum/rpc"
 	"golang.org/x/net/context"
 )
@@ -40,6 +41,14 @@ type EthApiBackend struct {
 	gpo *gasprice.GasPriceOracle
 }
 
+func (b *EthApiBackend) ChainConfig() *params.ChainConfig {
+	return b.eth.chainConfig
+}
+
+func (b *EthApiBackend) CurrentBlock() *types.Block {
+	return b.eth.blockchain.CurrentBlock()
+}
+
 func (b *EthApiBackend) SetHead(number uint64) {
 	b.eth.blockchain.SetHead(number)
 }
@@ -99,8 +108,7 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
 
 func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
 	statedb := state.(EthApiState).state
-	addr, _ := msg.From()
-	from := statedb.GetOrNewStateObject(addr)
+	from := statedb.GetOrNewStateObject(msg.From())
 	from.SetBalance(common.MaxBig)
 	vmError := func() error { return nil }
 	return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index f5f2437fa823..86638ae2d0ee 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -118,7 +118,8 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren
 		}
 		// If the block number is multiple of 3, send a bonus transaction to the miner
 		if parent == dl.genesis && i%3 == 0 {
-			tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey)
+			signer := types.MakeSigner(params.TestChainConfig, block.Number())
+			tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
 			if err != nil {
 				panic(err)
 			}
diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go
index 5d46c62fd9d7..426bfd5428a3 100644
--- a/eth/fetcher/fetcher_test.go
+++ b/eth/fetcher/fetcher_test.go
@@ -50,7 +50,8 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
 
 		// If the block number is multiple of 3, send a bonus transaction to the miner
 		if parent == genesis && i%3 == 0 {
-			tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey)
+			signer := types.MakeSigner(params.TestChainConfig, block.Number())
+			tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
 			if err != nil {
 				panic(err)
 			}
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 045bad0d4ae0..f599e9e8699b 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -305,18 +305,19 @@ func testGetNodeData(t *testing.T, protocol int) {
 	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
 	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
 
+	signer := types.HomesteadSigner{}
 	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
 	generator := func(i int, block *core.BlockGen) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+			tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
-			tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
+			tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
+			tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
 		case 2:
@@ -396,18 +397,19 @@ func testGetReceipt(t *testing.T, protocol int) {
 	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
 	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
 
+	signer := types.HomesteadSigner{}
 	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
 	generator := func(i int, block *core.BlockGen) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+			tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
-			tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
+			tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
+			tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
 		case 2:
diff --git a/eth/helper_test.go b/eth/helper_test.go
index 73af04fcf6a1..f239767850a7 100644
--- a/eth/helper_test.go
+++ b/eth/helper_test.go
@@ -110,7 +110,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
 
 	batches := make(map[common.Address]types.Transactions)
 	for _, tx := range p.pool {
-		from, _ := tx.From()
+		from, _ := types.Sender(types.HomesteadSigner{}, tx)
 		batches[from] = append(batches[from], tx)
 	}
 	for _, batch := range batches {
@@ -122,7 +122,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
 // newTestTransaction create a new dummy transaction.
 func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
 	tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
-	tx, _ = tx.SignECDSA(from)
+	tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
 	return tx
 }
 
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 6e2b1378a734..a095aa076725 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -147,7 +147,7 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*typ
 	var tx *types.Transaction
 	err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
 	if err == nil {
-		if _, r, _ := tx.SignatureValues(); r == nil {
+		if _, r, _ := tx.RawSignatureValues(); r == nil {
 			return nil, fmt.Errorf("server returned transaction without signature")
 		}
 	}
@@ -166,7 +166,11 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
 	var tx *types.Transaction
 	err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index)
 	if err == nil {
-		if _, r, _ := tx.SignatureValues(); r == nil {
+		var signer types.Signer = types.HomesteadSigner{}
+		if tx.Protected() {
+			signer = types.NewEIP155Signer(tx.ChainId())
+		}
+		if _, r, _ := types.SignatureValues(signer, tx); r == nil {
 			return nil, fmt.Errorf("server returned transaction without signature")
 		}
 	}
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 36bb8c077c30..0e4dd45240b5 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -279,7 +279,8 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
 		tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
 	}
 
-	signature, err := s.am.SignWithPassphrase(args.From, passwd, tx.SigHash().Bytes())
+	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
+	signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes())
 	if err != nil {
 		return common.Hash{}, err
 	}
@@ -537,22 +538,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
 	}
 
 	// Assemble the CALL invocation
-	msg := callmsg{
-		addr:     addr,
-		to:       args.To,
-		gas:      args.Gas.BigInt(),
-		gasPrice: args.GasPrice.BigInt(),
-		value:    args.Value.BigInt(),
-		data:     common.FromHex(args.Data),
+	gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt()
+	if gas.Cmp(common.Big0) == 0 {
+		gas = big.NewInt(50000000)
 	}
-
-	if msg.gas.Cmp(common.Big0) == 0 {
-		msg.gas = big.NewInt(50000000)
-	}
-
-	if msg.gasPrice.Cmp(common.Big0) == 0 {
-		msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
+	if gasPrice.Cmp(common.Big0) == 0 {
+		gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
 	}
+	msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data))
 
 	// Execute the call and return
 	vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
@@ -714,8 +707,12 @@ type RPCTransaction struct {
 
 // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
 func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
-	from, _ := tx.FromFrontier()
-	v, r, s := tx.SignatureValues()
+	var signer types.Signer = types.FrontierSigner{}
+	if tx.Protected() {
+		signer = types.NewEIP155Signer(tx.ChainId())
+	}
+	from, _ := types.Sender(signer, tx)
+	v, r, s := types.SignatureValues(signer, tx)
 	return &RPCTransaction{
 		From:     from,
 		Gas:      rpc.NewHexNumber(tx.Gas()),
@@ -735,11 +732,12 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
 func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) {
 	if txIndex >= 0 && txIndex < len(b.Transactions()) {
 		tx := b.Transactions()[txIndex]
-		from, err := tx.FromFrontier()
-		if err != nil {
-			return nil, err
+		var signer types.Signer = types.FrontierSigner{}
+		if tx.Protected() {
+			signer = types.NewEIP155Signer(tx.ChainId())
 		}
-		v, r, s := tx.SignatureValues()
+		from, _ := types.Sender(signer, tx)
+		v, r, s := tx.RawSignatureValues()
 		return &RPCTransaction{
 			BlockHash:        b.Hash(),
 			BlockNumber:      rpc.NewHexNumber(b.Number()),
@@ -958,11 +956,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
 		return nil, nil
 	}
 
-	from, err := tx.FromFrontier()
-	if err != nil {
-		glog.V(logger.Debug).Infof("%v\n", err)
-		return nil, nil
+	var signer types.Signer = types.FrontierSigner{}
+	if tx.Protected() {
+		signer = types.NewEIP155Signer(tx.ChainId())
 	}
+	from, _ := types.Sender(signer, tx)
 
 	fields := map[string]interface{}{
 		"root":              rpc.HexBytes(receipt.PostState),
@@ -990,11 +988,13 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
 
 // sign is a helper function that signs a transaction with the private key of the given address.
 func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
-	signature, err := s.b.AccountManager().SignEthereum(addr, tx.SigHash().Bytes())
+	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
+
+	signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes())
 	if err != nil {
 		return nil, err
 	}
-	return tx.WithSignature(signature)
+	return tx.WithSignature(signer, signature)
 }
 
 // SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
@@ -1028,7 +1028,9 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA
 
 // submitTransaction is a helper function that submits tx to txPool and creates a log entry.
 func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) {
-	signedTx, err := tx.WithSignature(signature)
+	signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
+
+	signedTx, err := tx.WithSignature(signer, signature)
 	if err != nil {
 		return common.Hash{}, err
 	}
@@ -1038,7 +1040,7 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si
 	}
 
 	if signedTx.To() == nil {
-		from, _ := signedTx.From()
+		from, _ := types.Sender(signer, signedTx)
 		addr := crypto.CreateAddress(from, signedTx.Nonce())
 		glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
 	} else {
@@ -1072,7 +1074,8 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
 		tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
 	}
 
-	signature, err := s.b.AccountManager().SignEthereum(args.From, tx.SigHash().Bytes())
+	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
+	signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes())
 	if err != nil {
 		return common.Hash{}, err
 	}
@@ -1092,8 +1095,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
 		return "", err
 	}
 
+	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
 	if tx.To() == nil {
-		from, err := tx.FromFrontier()
+		from, err := types.Sender(signer, tx)
 		if err != nil {
 			return "", err
 		}
@@ -1202,7 +1206,12 @@ type SignTransactionResult struct {
 }
 
 func newTx(t *types.Transaction) *Tx {
-	from, _ := t.FromFrontier()
+	var signer types.Signer = types.HomesteadSigner{}
+	if t.Protected() {
+		signer = types.NewEIP155Signer(t.ChainId())
+	}
+
+	from, _ := types.Sender(signer, t)
 	return &Tx{
 		tx:       t,
 		To:       t.To(),
@@ -1268,7 +1277,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
 	pending := s.b.GetPoolTransactions()
 	transactions := make([]*RPCTransaction, 0, len(pending))
 	for _, tx := range pending {
-		from, _ := tx.FromFrontier()
+		var signer types.Signer = types.HomesteadSigner{}
+		if tx.Protected() {
+			signer = types.NewEIP155Signer(tx.ChainId())
+		}
+		from, _ := types.Sender(signer, tx)
 		if s.b.AccountManager().HasAddress(from) {
 			transactions = append(transactions, newRPCPendingTransaction(tx))
 		}
@@ -1281,7 +1294,12 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
 func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {
 	pending := s.b.GetPoolTransactions()
 	for _, p := range pending {
-		if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() {
+		var signer types.Signer = types.HomesteadSigner{}
+		if p.Protected() {
+			signer = types.NewEIP155Signer(p.ChainId())
+		}
+
+		if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) {
 			if gasPrice == nil {
 				gasPrice = rpc.NewHexNumber(tx.tx.GasPrice())
 			}
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index f9358b6cfd3d..fdc4a39dc8a8 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -28,6 +28,7 @@ import (
 	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
 	"golang.org/x/net/context"
 )
@@ -59,6 +60,9 @@ type Backend interface {
 	GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
 	Stats() (pending int, queued int)
 	TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
+
+	ChainConfig() *params.ChainConfig
+	CurrentBlock() *types.Block
 }
 
 type State interface {
diff --git a/les/api_backend.go b/les/api_backend.go
index 42d6cc473313..b77767ed70e4 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -30,6 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/light"
+	"github.com/ethereum/go-ethereum/params"
 	rpc "github.com/ethereum/go-ethereum/rpc"
 	"golang.org/x/net/context"
 )
@@ -39,6 +40,14 @@ type LesApiBackend struct {
 	gpo *gasprice.LightPriceOracle
 }
 
+func (b *LesApiBackend) ChainConfig() *params.ChainConfig {
+	return b.eth.chainConfig
+}
+
+func (b *LesApiBackend) CurrentBlock() *types.Block {
+	return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader())
+}
+
 func (b *LesApiBackend) SetHead(number uint64) {
 	b.eth.blockchain.SetHead(number)
 }
@@ -81,7 +90,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
 
 func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
 	stateDb := state.(*light.LightState).Copy()
-	addr, _ := msg.From()
+	addr := msg.From()
 	from, err := stateDb.GetOrNewStateObject(ctx, addr)
 	if err != nil {
 		return nil, nil, err
diff --git a/les/helper_test.go b/les/helper_test.go
index 9569f2f75539..a5428e954f72 100644
--- a/les/helper_test.go
+++ b/les/helper_test.go
@@ -73,20 +73,22 @@ contract test {
 */
 
 func testChainGen(i int, block *core.BlockGen) {
+	signer := types.HomesteadSigner{}
+
 	switch i {
 	case 0:
 		// In block 1, the test bank sends account #1 some ether.
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	case 1:
 		// In block 2, the test bank sends some more ether to account #1.
 		// acc1Addr passes it on to account #2.
 		// acc1Addr creates a test contract.
-		tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+		tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 		nonce := block.TxNonce(acc1Addr)
-		tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
+		tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
 		nonce++
-		tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(acc1Key)
+		tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
 		testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
 		block.AddTx(tx1)
 		block.AddTx(tx2)
@@ -96,7 +98,7 @@ func testChainGen(i int, block *core.BlockGen) {
 		block.SetCoinbase(acc2Addr)
 		block.SetExtra([]byte("yeehaw"))
 		data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	case 3:
 		// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
@@ -107,7 +109,7 @@ func testChainGen(i int, block *core.BlockGen) {
 		b3.Extra = []byte("foo")
 		block.AddUncle(b3)
 		data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	}
 }
@@ -214,7 +216,7 @@ func (p *testTxPool) GetTransactions() types.Transactions {
 // newTestTransaction create a new dummy transaction.
 func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
 	tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
-	tx, _ = tx.SignECDSA(from)
+	tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
 
 	return tx
 }
diff --git a/les/odr_test.go b/les/odr_test.go
index e7084bc20aef..f1fa59ad83be 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -100,45 +100,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainCon
 
 func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) }
 
-// fullcallmsg is the message type used for call transations.
-type fullcallmsg struct {
-	from          *state.StateObject
-	to            *common.Address
-	gas, gasPrice *big.Int
-	value         *big.Int
-	data          []byte
+type callmsg struct {
+	types.Message
 }
 
-// accessor boilerplate to implement core.Message
-func (m fullcallmsg) From() (common.Address, error)         { return m.from.Address(), nil }
-func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
-func (m fullcallmsg) Nonce() uint64                         { return 0 }
-func (m fullcallmsg) CheckNonce() bool                      { return false }
-func (m fullcallmsg) To() *common.Address                   { return m.to }
-func (m fullcallmsg) GasPrice() *big.Int                    { return m.gasPrice }
-func (m fullcallmsg) Gas() *big.Int                         { return m.gas }
-func (m fullcallmsg) Value() *big.Int                       { return m.value }
-func (m fullcallmsg) Data() []byte                          { return m.data }
-
-// callmsg is the message type used for call transations.
-type lightcallmsg struct {
-	from          *light.StateObject
-	to            *common.Address
-	gas, gasPrice *big.Int
-	value         *big.Int
-	data          []byte
-}
-
-// accessor boilerplate to implement core.Message
-func (m lightcallmsg) From() (common.Address, error)         { return m.from.Address(), nil }
-func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
-func (m lightcallmsg) Nonce() uint64                         { return 0 }
-func (m lightcallmsg) CheckNonce() bool                      { return false }
-func (m lightcallmsg) To() *common.Address                   { return m.to }
-func (m lightcallmsg) GasPrice() *big.Int                    { return m.gasPrice }
-func (m lightcallmsg) Gas() *big.Int                         { return m.gas }
-func (m lightcallmsg) Value() *big.Int                       { return m.value }
-func (m lightcallmsg) Data() []byte                          { return m.data }
+func (callmsg) CheckNonce() bool { return false }
 
 func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
 	data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
@@ -153,15 +119,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
 				from := statedb.GetOrNewStateObject(testBankAddress)
 				from.SetBalance(common.MaxBig)
 
-				msg := fullcallmsg{
-					from:     from,
-					gas:      big.NewInt(100000),
-					gasPrice: big.NewInt(0),
-					value:    big.NewInt(0),
-					data:     data,
-					to:       &testContractAddr,
-				}
-
+				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)}
 				vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
 				ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
@@ -174,14 +132,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
 			if err == nil {
 				from.SetBalance(common.MaxBig)
 
-				msg := lightcallmsg{
-					from:     from,
-					gas:      big.NewInt(100000),
-					gasPrice: big.NewInt(0),
-					value:    big.NewInt(0),
-					data:     data,
-					to:       &testContractAddr,
-				}
+				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)}
 
 				vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
diff --git a/light/odr_test.go b/light/odr_test.go
index 1ae600e2830e..1f6bcaeb147a 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -148,45 +148,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
 
 func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) }
 
-// fullcallmsg is the message type used for call transations.
-type fullcallmsg struct {
-	from          *state.StateObject
-	to            *common.Address
-	gas, gasPrice *big.Int
-	value         *big.Int
-	data          []byte
+type callmsg struct {
+	types.Message
 }
 
-// accessor boilerplate to implement core.Message
-func (m fullcallmsg) From() (common.Address, error)         { return m.from.Address(), nil }
-func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
-func (m fullcallmsg) Nonce() uint64                         { return 0 }
-func (m fullcallmsg) CheckNonce() bool                      { return false }
-func (m fullcallmsg) To() *common.Address                   { return m.to }
-func (m fullcallmsg) GasPrice() *big.Int                    { return m.gasPrice }
-func (m fullcallmsg) Gas() *big.Int                         { return m.gas }
-func (m fullcallmsg) Value() *big.Int                       { return m.value }
-func (m fullcallmsg) Data() []byte                          { return m.data }
-
-// callmsg is the message type used for call transations.
-type lightcallmsg struct {
-	from          *StateObject
-	to            *common.Address
-	gas, gasPrice *big.Int
-	value         *big.Int
-	data          []byte
-}
-
-// accessor boilerplate to implement core.Message
-func (m lightcallmsg) From() (common.Address, error)         { return m.from.Address(), nil }
-func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
-func (m lightcallmsg) Nonce() uint64                         { return 0 }
-func (m lightcallmsg) CheckNonce() bool                      { return false }
-func (m lightcallmsg) To() *common.Address                   { return m.to }
-func (m lightcallmsg) GasPrice() *big.Int                    { return m.gasPrice }
-func (m lightcallmsg) Gas() *big.Int                         { return m.gas }
-func (m lightcallmsg) Value() *big.Int                       { return m.value }
-func (m lightcallmsg) Data() []byte                          { return m.data }
+func (callmsg) CheckNonce() bool { return false }
 
 func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte {
 	data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
@@ -201,15 +167,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
 				from := statedb.GetOrNewStateObject(testBankAddress)
 				from.SetBalance(common.MaxBig)
 
-				msg := fullcallmsg{
-					from:     from,
-					gas:      big.NewInt(100000),
-					gasPrice: big.NewInt(0),
-					value:    big.NewInt(0),
-					data:     data,
-					to:       &testContractAddr,
-				}
-
+				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)}
 				vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
 				ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
@@ -222,15 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
 			if err == nil {
 				from.SetBalance(common.MaxBig)
 
-				msg := lightcallmsg{
-					from:     from,
-					gas:      big.NewInt(100000),
-					gasPrice: big.NewInt(0),
-					value:    big.NewInt(0),
-					data:     data,
-					to:       &testContractAddr,
-				}
-
+				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)}
 				vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
 				ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
@@ -244,20 +194,21 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
 }
 
 func testChainGen(i int, block *core.BlockGen) {
+	signer := types.HomesteadSigner{}
 	switch i {
 	case 0:
 		// In block 1, the test bank sends account #1 some ether.
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	case 1:
 		// In block 2, the test bank sends some more ether to account #1.
 		// acc1Addr passes it on to account #2.
 		// acc1Addr creates a test contract.
-		tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+		tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
 		nonce := block.TxNonce(acc1Addr)
-		tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
+		tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
 		nonce++
-		tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(acc1Key)
+		tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
 		testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
 		block.AddTx(tx1)
 		block.AddTx(tx2)
@@ -267,7 +218,7 @@ func testChainGen(i int, block *core.BlockGen) {
 		block.SetCoinbase(acc2Addr)
 		block.SetExtra([]byte("yeehaw"))
 		data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	case 3:
 		// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
@@ -278,7 +229,7 @@ func testChainGen(i int, block *core.BlockGen) {
 		b3.Extra = []byte("foo")
 		block.AddUncle(b3)
 		data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
-		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
+		tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
 		block.AddTx(tx)
 	}
 }
diff --git a/light/txpool.go b/light/txpool.go
index c046cac25356..309bc3a322f3 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -44,6 +44,7 @@ var txPermanent = uint64(500)
 // created.
 type TxPool struct {
 	config   *params.ChainConfig
+	signer   types.Signer
 	quit     chan bool
 	eventMux *event.TypeMux
 	events   event.Subscription
@@ -80,6 +81,7 @@ type TxRelayBackend interface {
 func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
 	pool := &TxPool{
 		config:   config,
+		signer:   types.HomesteadSigner{},
 		nonce:    make(map[common.Address]uint64),
 		pending:  make(map[common.Hash]*types.Transaction),
 		mined:    make(map[common.Hash][]*types.Transaction),
@@ -198,7 +200,7 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uin
 				if len(receipts) != len(block.Transactions()) {
 					panic(nil) // should never happen if hashes did match
 				}
-				core.SetReceiptsData(block, receipts)
+				core.SetReceiptsData(pool.config, block, receipts)
 			}
 			//fmt.Println("WriteReceipt", receipts[i].TxHash)
 			core.WriteReceipt(pool.chainDb, receipts[i])
@@ -309,6 +311,7 @@ func (pool *TxPool) eventLoop() {
 			m, r := txc.getLists()
 			pool.relay.NewHead(pool.head, m, r)
 			pool.homestead = pool.config.IsHomestead(head.Number)
+			pool.signer = types.MakeSigner(pool.config, head.Number)
 			pool.mu.Unlock()
 		}
 	}
@@ -340,7 +343,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
 
 	// Validate the transaction sender and it's sig. Throw
 	// if the from fields is invalid.
-	if from, err = tx.From(); err != nil {
+	if from, err = types.Sender(pool.signer, tx); err != nil {
 		return core.ErrInvalidSender
 	}
 
@@ -389,7 +392,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
 	}
 
 	// Should supply enough intrinsic gas
-	if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), core.MessageCreatesContract(tx), pool.homestead)) < 0 {
+	if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)) < 0 {
 		return core.ErrIntrinsicGas
 	}
 
@@ -413,7 +416,8 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
 		self.pending[hash] = tx
 
 		nonce := tx.Nonce() + 1
-		addr, _ := tx.From()
+
+		addr, _ := types.Sender(self.signer, tx)
 		if nonce > self.nonce[addr] {
 			self.nonce[addr] = nonce
 		}
@@ -433,7 +437,7 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
 		}
 		// we can ignore the error here because From is
 		// verified in ValidateTransaction.
-		f, _ := tx.From()
+		f, _ := types.Sender(self.signer, tx)
 		from := common.Bytes2Hex(f[:4])
 		glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash)
 	}
@@ -518,7 +522,7 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common
 	// Retrieve all the pending transactions and sort by account and by nonce
 	pending := make(map[common.Address]types.Transactions)
 	for _, tx := range self.pending {
-		account, _ := tx.From()
+		account, _ := types.Sender(self.signer, tx)
 		pending[account] = append(pending[account], tx)
 	}
 	// There are no queued transactions in a light pool, just return an empty map
diff --git a/light/txpool_test.go b/light/txpool_test.go
index 0f797a9e8169..759b6b8ab720 100644
--- a/light/txpool_test.go
+++ b/light/txpool_test.go
@@ -74,7 +74,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
 
 func TestTxPool(t *testing.T) {
 	for i, _ := range testTx {
-		testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
+		testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(types.HomesteadSigner{}, testBankKey)
 	}
 
 	var (
diff --git a/light/vm_env.go b/light/vm_env.go
index 82008a929e10..5d330b072ad2 100644
--- a/light/vm_env.go
+++ b/light/vm_env.go
@@ -61,7 +61,7 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainCon
 
 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 }
diff --git a/miner/worker.go b/miner/worker.go
index f98145e8ff54..2933b6bd3bd4 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -63,7 +63,9 @@ type uint64RingBuffer struct {
 // Work is the workers current environment and holds
 // all of the current state information
 type Work struct {
-	config           *params.ChainConfig
+	config *params.ChainConfig
+	signer types.Signer
+
 	state            *state.StateDB // apply state changes here
 	ancestors        *set.Set       // ancestor set (used for checking uncle parent validity)
 	family           *set.Set       // family set (used for checking uncle invalidity)
@@ -235,7 +237,7 @@ func (self *worker) update() {
 			if atomic.LoadInt32(&self.mining) == 0 {
 				self.currentMu.Lock()
 
-				acc, _ := ev.Tx.From()
+				acc, _ := types.Sender(self.current.signer, ev.Tx)
 				txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}}
 				txset := types.NewTransactionsByPriceAndNonce(txs)
 
@@ -367,6 +369,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
 	}
 	work := &Work{
 		config:    self.config,
+		signer:    types.NewEIP155Signer(self.config.ChainId),
 		state:     state,
 		ancestors: set.New(),
 		family:    set.New(),
@@ -570,7 +573,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
 		}
 		// Error may be ignored here. The error has already been checked
 		// during transaction acceptance is the transaction pool.
-		from, _ := tx.From()
+		//
+		// We use the eip155 signer regardless of the current hf.
+		from, _ := types.Sender(env.signer, tx)
+		// Check whether the tx is replay protected. If we're not in the EIP155 hf
+		// phase, start ignoring the sender until we do.
+		if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
+			glog.V(logger.Detail).Infof("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash())
+
+			txs.Pop()
+			continue
+		}
 
 		// Ignore any transactions (and accounts subsequently) with low gas limits
 		if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
diff --git a/params/config.go b/params/config.go
index 684e4dc421aa..d63236ef839f 100644
--- a/params/config.go
+++ b/params/config.go
@@ -28,18 +28,24 @@ import (
 // that any network, identified by its genesis block, can have its own
 // set of configuration options.
 type ChainConfig struct {
+	ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection
+
 	HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
 	DAOForkBlock   *big.Int `json:"daoForkBlock"`   // TheDAO hard-fork switch block (nil = no fork)
 	DAOForkSupport bool     `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
 
 	// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
-	EIP150Block *big.Int    `json:"EIP150Block"` // EIP150 HF block (nil = no fork)
-	EIP150Hash  common.Hash `json:"EIP150Hash"`  // EIP150 HF hash (fast sync aid)
+	EIP150Block *big.Int    `json:"eip150Block"` // EIP150 HF block (nil = no fork)
+	EIP150Hash  common.Hash `json:"eip150Hash"`  // EIP150 HF hash (fast sync aid)
 
-	EIP158Block *big.Int `json:"EIP158Block"` // EIP158 HF block
+	EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block
+	EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
 }
 
-var TestChainConfig = &ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int)}
+var (
+	TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
+	TestRules       = TestChainConfig.Rules(new(big.Int))
+)
 
 // IsHomestead returns whether num is either equal to the homestead block or greater.
 func (c *ChainConfig) IsHomestead(num *big.Int) bool {
@@ -75,6 +81,14 @@ func (c *ChainConfig) IsEIP150(num *big.Int) bool {
 
 }
 
+func (c *ChainConfig) IsEIP155(num *big.Int) bool {
+	if c.EIP155Block == nil || num == nil {
+		return false
+	}
+	return num.Cmp(c.EIP155Block) >= 0
+
+}
+
 func (c *ChainConfig) IsEIP158(num *big.Int) bool {
 	if c.EIP158Block == nil || num == nil {
 		return false
@@ -82,3 +96,17 @@ func (c *ChainConfig) IsEIP158(num *big.Int) bool {
 	return num.Cmp(c.EIP158Block) >= 0
 
 }
+
+// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
+// that do not have or require information about the block.
+//
+// Rules is a one time interface meaning that it shouldn't be used in between transition
+// phases.
+type Rules struct {
+	ChainId                                   *big.Int
+	IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
+}
+
+func (c *ChainConfig) Rules(num *big.Int) Rules {
+	return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)}
+}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index c8899392ad2a..c08398321c8f 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -29,6 +29,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
@@ -225,7 +226,7 @@ func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx m
 
 	key, _ := hex.DecodeString(tx["secretKey"])
 	addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
-	message := NewMessage(addr, to, data, value, gas, price, nonce)
+	message := types.NewMessage(addr, to, nonce, value, gas, price, data)
 	vmenv := NewEnvFromMap(chainConfig, statedb, env, tx)
 	vmenv.origin = addr
 
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index be351473733c..184bdee2a8b2 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -159,16 +159,11 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e
 		}
 	}()
 
-	var (
-		decodedSender common.Address
-	)
+	var decodedSender common.Address
 
 	chainConfig := &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock}
-	if chainConfig.IsHomestead(common.String2Big(txTest.Blocknumber)) {
-		decodedSender, err = decodedTx.From()
-	} else {
-		decodedSender, err = decodedTx.FromFrontier()
-	}
+	signer := types.MakeSigner(chainConfig, common.String2Big(txTest.Blocknumber))
+	decodedSender, err = types.Sender(signer, decodedTx)
 	if err != nil {
 		return err
 	}
@@ -198,7 +193,7 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e
 		return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce())
 	}
 
-	v, r, s := decodedTx.SignatureValues()
+	v, r, s := types.SignatureValues(signer, decodedTx)
 	expectedR := mustConvertBigInt(txTest.Transaction.R, 16)
 	if r.Cmp(expectedR) != 0 {
 		return fmt.Errorf("R mismatch: %v %v", expectedR, r)
diff --git a/tests/util.go b/tests/util.go
index 5296bb54bc41..53955a47fa65 100644
--- a/tests/util.go
+++ b/tests/util.go
@@ -282,26 +282,3 @@ func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *b
 		return core.Create(self, caller, data, gas, price, value)
 	}
 }
-
-type Message struct {
-	from              common.Address
-	to                *common.Address
-	value, gas, price *big.Int
-	data              []byte
-	nonce             uint64
-}
-
-func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int, nonce uint64) Message {
-	return Message{from, to, value, gas, price, data, nonce}
-}
-
-func (self Message) Hash() []byte                          { return nil }
-func (self Message) From() (common.Address, error)         { return self.from, nil }
-func (self Message) FromFrontier() (common.Address, error) { return self.from, nil }
-func (self Message) To() *common.Address                   { return self.to }
-func (self Message) GasPrice() *big.Int                    { return self.price }
-func (self Message) Gas() *big.Int                         { return self.gas }
-func (self Message) Value() *big.Int                       { return self.value }
-func (self Message) Nonce() uint64                         { return self.nonce }
-func (self Message) CheckNonce() bool                      { return true }
-func (self Message) Data() []byte                          { return self.data }
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index f00af87b9e46..50660134b7d6 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -225,7 +225,12 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs,
 
 	caller := state.GetOrNewStateObject(from)
 
-	vmenv := NewEnvFromMap(&params.ChainConfig{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true, nil, common.Hash{}, nil}, state, env, exec)
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: params.MainNetHomesteadBlock,
+		DAOForkBlock:   params.MainNetDAOForkBlock,
+		DAOForkSupport: true,
+	}
+	vmenv := NewEnvFromMap(chainConfig, state, env, exec)
 	vmenv.vmTest = true
 	vmenv.skipTransfer = true
 	vmenv.initial = true