diff --git a/core/bench_test.go b/core/bench_test.go
index 79c369d5fcfb4952382bd02ae7a7c41aa2e2e4cb..d7a5e11c2f15f62fdc49321b6f0332428bd1bda0 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
 	return func(i int, gen *BlockGen) {
 		toaddr := common.Address{}
 		data := make([]byte, nbytes)
-		gas, _ := IntrinsicGas(data, false, false)
+		gas, _ := IntrinsicGas(data, false, false, false)
 		tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
 		gen.AddTx(tx)
 	}
diff --git a/core/state_transition.go b/core/state_transition.go
index fda081b7d11351e4e5624760ed6a4a0b0f566a06..bef6e9b0eb2f9969b82196be8c39f5c78fc01009 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -76,10 +76,10 @@ type Message interface {
 }
 
 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
-func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) {
+func IntrinsicGas(data []byte, contractCreation, isEIP155 bool, isEIP2028 bool) (uint64, error) {
 	// Set the starting gas for the raw transaction
 	var gas uint64
-	if contractCreation && homestead {
+	if contractCreation && isEIP155 {
 		gas = params.TxGasContractCreation
 	} else {
 		gas = params.TxGas
@@ -94,10 +94,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error)
 			}
 		}
 		// Make sure we don't exceed uint64 for all data combinations
-		if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz {
+		nonZeroGas := params.TxDataNonZeroGasFrontier
+		if isEIP2028 {
+			nonZeroGas = params.TxDataNonZeroGasEIP2028
+		}
+		if (math.MaxUint64-gas)/nonZeroGas < nz {
 			return 0, vm.ErrOutOfGas
 		}
-		gas += nz * params.TxDataNonZeroGas
+		gas += nz * nonZeroGas
 
 		z := uint64(len(data)) - nz
 		if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
@@ -187,10 +191,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
 	msg := st.msg
 	sender := vm.AccountRef(msg.From())
 	homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
+	istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
 	contractCreation := msg.To() == nil
 
 	// Pay intrinsic gas
-	gas, err := IntrinsicGas(st.data, contractCreation, homestead)
+	gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
 	if err != nil {
 		return nil, 0, false, err
 	}
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 0c422dd99d9217591f2a25044ceedbf091f3f7df..a49b422614215fd19f7dea18855ae50e2e33e5e2 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -217,6 +217,8 @@ type TxPool struct {
 	signer      types.Signer
 	mu          sync.RWMutex
 
+	istanbul bool // Fork indicator whether we are in the istanbul stage.
+
 	currentState  *state.StateDB // Current state in the blockchain head
 	pendingNonces *txNoncer      // Pending state tracking virtual nonces
 	currentMaxGas uint64         // Current gas limit for transaction caps
@@ -540,7 +542,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
 		return ErrInsufficientFunds
 	}
 	// Ensure the transaction has more gas than the basic tx fee.
-	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true)
+	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
 	if err != nil {
 		return err
 	}
@@ -1118,6 +1120,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
 	log.Debug("Reinjecting stale transactions", "count", len(reinject))
 	senderCacher.recover(pool.signer, reinject)
 	pool.addTxsLocked(reinject, false)
+
+	// Update all fork indicator by next pending block number.
+	next := new(big.Int).Add(newHead.Number, big.NewInt(1))
+	pool.istanbul = pool.chainconfig.IsIstanbul(next)
 }
 
 // promoteExecutables moves transactions that have become processable from the
diff --git a/light/txpool.go b/light/txpool.go
index e945ef2ec178648af7ce2f2f5000b04ba07c0169..11a0e76ae01e43003960ef095200ca06468032f6 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -19,6 +19,7 @@ package light
 import (
 	"context"
 	"fmt"
+	"math/big"
 	"sync"
 	"time"
 
@@ -67,7 +68,7 @@ type TxPool struct {
 	mined        map[common.Hash][]*types.Transaction // mined transactions by block hash
 	clearIdx     uint64                               // earliest block nr that can contain mined tx info
 
-	homestead bool
+	istanbul bool // Fork indicator whether we are in the istanbul stage.
 }
 
 // TxRelayBackend provides an interface to the mechanism that forwards transacions
@@ -309,8 +310,10 @@ func (pool *TxPool) setNewHead(head *types.Header) {
 	txc, _ := pool.reorgOnNewHead(ctx, head)
 	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)
+
+	// Update fork indicator by next pending block number
+	next := new(big.Int).Add(head.Number, big.NewInt(1))
+	pool.istanbul = pool.config.IsIstanbul(next)
 }
 
 // Stop stops the light transaction pool
@@ -378,7 +381,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
 	}
 
 	// Should supply enough intrinsic gas
-	gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
+	gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
 	if err != nil {
 		return err
 	}
diff --git a/params/protocol_params.go b/params/protocol_params.go
index 943788be8cf2e4539067fb80989f03a951bafd6a..3022b700df9a2b73b86b42c8619156c70108f753 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -55,19 +55,20 @@ const (
 	JumpdestGas   uint64 = 1     // Once per JUMPDEST operation.
 	EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
 
-	CreateDataGas         uint64 = 200   //
-	CallCreateDepth       uint64 = 1024  // Maximum depth of call/create stack.
-	ExpGas                uint64 = 10    // Once per EXP instruction
-	LogGas                uint64 = 375   // Per LOG* operation.
-	CopyGas               uint64 = 3     //
-	StackLimit            uint64 = 1024  // Maximum size of VM stack allowed.
-	TierStepGas           uint64 = 0     // Once per operation, for a selection of them.
-	LogTopicGas           uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
-	CreateGas             uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
-	Create2Gas            uint64 = 32000 // Once per CREATE2 operation
-	SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
-	MemoryGas             uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
-	TxDataNonZeroGas      uint64 = 68    // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+	CreateDataGas            uint64 = 200   //
+	CallCreateDepth          uint64 = 1024  // Maximum depth of call/create stack.
+	ExpGas                   uint64 = 10    // Once per EXP instruction
+	LogGas                   uint64 = 375   // Per LOG* operation.
+	CopyGas                  uint64 = 3     //
+	StackLimit               uint64 = 1024  // Maximum size of VM stack allowed.
+	TierStepGas              uint64 = 0     // Once per operation, for a selection of them.
+	LogTopicGas              uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
+	CreateGas                uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
+	Create2Gas               uint64 = 32000 // Once per CREATE2 operation
+	SelfdestructRefundGas    uint64 = 24000 // Refunded following a selfdestruct operation.
+	MemoryGas                uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+	TxDataNonZeroGasFrontier uint64 = 68    // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+	TxDataNonZeroGasEIP2028  uint64 = 16    // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
 
 	// These have been changed during the course of the chain
 	CallGasFrontier              uint64 = 40  // Once per CALL operation & message call transaction.
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index 12444720cc7a78c15f78d17d8e1905e661f74504..85bf1fb0bd0d4fe8c01a801a0a4ba5fa1a51dba6 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -32,6 +32,7 @@ type TransactionTest struct {
 	RLP            hexutil.Bytes `json:"rlp"`
 	Byzantium      ttFork
 	Constantinople ttFork
+	Istanbul       ttFork
 	EIP150         ttFork
 	EIP158         ttFork
 	Frontier       ttFork
@@ -45,7 +46,7 @@ type ttFork struct {
 
 func (tt *TransactionTest) Run(config *params.ChainConfig) error {
 
-	validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool) (*common.Address, *common.Hash, error) {
+	validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool, isIstanbul bool) (*common.Address, *common.Hash, error) {
 		tx := new(types.Transaction)
 		if err := rlp.DecodeBytes(rlpData, tx); err != nil {
 			return nil, nil, err
@@ -55,7 +56,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
 			return nil, nil, err
 		}
 		// Intrinsic gas
-		requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead)
+		requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead, isIstanbul)
 		if err != nil {
 			return nil, nil, err
 		}
@@ -71,19 +72,22 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
 		signer      types.Signer
 		fork        ttFork
 		isHomestead bool
+		isIstanbul  bool
 	}{
-		{"Frontier", types.FrontierSigner{}, tt.Frontier, false},
-		{"Homestead", types.HomesteadSigner{}, tt.Homestead, true},
-		{"EIP150", types.HomesteadSigner{}, tt.EIP150, true},
-		{"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true},
-		{"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true},
-		{"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true},
+		{"Frontier", types.FrontierSigner{}, tt.Frontier, false, false},
+		{"Homestead", types.HomesteadSigner{}, tt.Homestead, true, false},
+		{"EIP150", types.HomesteadSigner{}, tt.EIP150, true, false},
+		{"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false},
+		{"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false},
+		{"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false},
+		//TODO! @holiman or @rjl493456442 : enable this after tests have been updated for Istanbul
+		//{"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true},
 	} {
-		sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead)
+		sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul)
 
 		if testcase.fork.Sender == (common.UnprefixedAddress{}) {
 			if err == nil {
-				return fmt.Errorf("Expected error, got none (address %v)", sender.String())
+				return fmt.Errorf("Expected error, got none (address %v)[%v]", sender.String(), testcase.name)
 			}
 			continue
 		}