Add EthChainID and update signers accordingly for processing eth txns. (#3497)

* allow eth hmy txn conversion

* Add EthChainID and update signers for it

* resolve comments about hash()
pull/3314/head
Rongjian Lan 4 years ago committed by GitHub
parent 9381b95cdc
commit d6e98436f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      cmd/harmony/main.go
  2. 8
      core/blockchain.go
  3. 9
      core/state_processor.go
  4. 39
      core/types/eth_transaction.go
  5. 58
      core/types/transaction.go
  6. 13
      core/types/transaction_signing.go
  7. 2
      core/types/transaction_test.go
  8. 1
      core/vm/eips.go
  9. 11
      core/vm/runtime/runtime.go
  10. 3
      hmy/hmy.go
  11. 41
      hmy/tracer.go
  12. 258
      internal/params/config.go
  13. 18
      node/worker/worker.go
  14. 5
      staking/types/transaction.go

@ -16,6 +16,8 @@ import (
"syscall"
"time"
"github.com/harmony-one/harmony/internal/params"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/harmony-one/bls/ffi/go/bls"
@ -279,6 +281,9 @@ func setupNodeAndRun(hc harmonyConfig) {
nodeconfig.GetDefaultConfig().ShardID = nodeConfig.ShardID
nodeconfig.GetDefaultConfig().IsOffline = nodeConfig.IsOffline
// Update ethereum compatible chain ids
params.UpdateEthChainIDByShard(nodeConfig.ShardID)
// Check NTP configuration
accurate, err := ntp.CheckLocalTimeAccurate(nodeConfig.NtpServer)
if !accurate {

@ -956,6 +956,7 @@ func (bc *BlockChain) Rollback(chain []common.Hash) error {
// SetReceiptsData computes all the non-consensus fields of the receipts
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {
signer := types.MakeSigner(config, block.Epoch())
ethSigner := types.NewEIP155Signer(config.EthCompatibleChainID)
transactions, stakingTransactions, logIndex := block.Transactions(), block.StakingTransactions(), uint(0)
if len(transactions)+len(stakingTransactions) != len(receipts) {
@ -973,7 +974,12 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
// The contract address can be derived from the transaction itself
if transactions[j].To() == nil {
// Deriving the signer is expensive, only do if it's actually needed
from, _ := types.Sender(signer, transactions[j])
var from common.Address
if transactions[j].IsEthCompatible() {
from, _ = types.Sender(ethSigner, transactions[j])
} else {
from, _ = types.Sender(signer, transactions[j])
}
receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce())
}
// The derived log fields can simply be set from the block and transaction

@ -187,7 +187,14 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
)
}
msg, err := tx.AsMessage(types.MakeSigner(config, header.Epoch()))
var signer types.Signer
if tx.IsEthCompatible() {
signer = types.NewEIP155Signer(config.EthCompatibleChainID)
} else {
signer = types.MakeSigner(config, header.Epoch())
}
msg, err := tx.AsMessage(signer)
// skip signer err for additiononly tx
if err != nil {
return nil, nil, 0, err

@ -21,6 +21,8 @@ import (
"math/big"
"sync/atomic"
"github.com/harmony-one/harmony/internal/params"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/harmony/crypto/hash"
@ -32,9 +34,6 @@ import (
//go:generate gencodec -type ethTxdata -field-override ethTxdataMarshaling -out gen_eth_tx_json.go
// Shard0ChainID to be reserved unique chain ID for eth compatible chains.
const Shard0ChainID = 0
// EthTransaction ethereum-compatible transaction
type EthTransaction struct {
data ethTxdata
@ -152,12 +151,12 @@ func (tx *EthTransaction) Data() []byte {
// ShardID returns which shard id this transaction was signed for (if at all)
func (tx *EthTransaction) ShardID() uint32 {
return uint32(tx.ChainID().Uint64()) - Shard0ChainID
return uint32(tx.ChainID().Uint64() - params.EthMainnetChainID.Uint64())
}
// ToShardID returns the destination shard id this transaction is going to
func (tx *EthTransaction) ToShardID() uint32 {
return uint32(tx.ChainID().Uint64()) - Shard0ChainID
return uint32(tx.ChainID().Uint64() - params.EthMainnetChainID.Uint64())
}
// ChainID returns which chain id this transaction was signed for (if at all)
@ -177,6 +176,31 @@ func (tx *EthTransaction) Copy() *EthTransaction {
return &tx2
}
// ConvertToHmy converts eth txn to hmy txn by filling in ShardID and ToShardID fields.
func (tx *EthTransaction) ConvertToHmy() *Transaction {
var tx2 Transaction
d := &tx.data
d2 := &tx2.data
d2.AccountNonce = d.AccountNonce
d2.Price = new(big.Int).Set(d.Price)
d2.GasLimit = d.GasLimit
d2.Recipient = copyAddr(d.Recipient)
d2.Amount = new(big.Int).Set(d.Amount)
d2.Payload = append(d.Payload[:0:0], d.Payload...)
d2.V = new(big.Int).Set(d.V)
d2.R = new(big.Int).Set(d.R)
d2.S = new(big.Int).Set(d.S)
d2.ShardID = tx.ShardID()
d2.ToShardID = tx.ToShardID()
copy := tx2.Hash()
d2.Hash = &copy
return &tx2
}
// EncodeRLP implements rlp.Encoder
func (tx *EthTransaction) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &tx.data)
@ -302,6 +326,11 @@ func (tx *EthTransaction) SenderAddress() (common.Address, error) {
return addr, nil
}
// IsEthCompatible returns whether the txn is ethereum compatible
func (tx *EthTransaction) IsEthCompatible() bool {
return true
}
// AsMessage returns the transaction as a core.Message.
//
// AsMessage requires a signer to derive the sender.

@ -24,6 +24,8 @@ import (
"math/big"
"sync/atomic"
"github.com/harmony-one/harmony/internal/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
@ -70,6 +72,7 @@ type InternalTransaction interface {
R() *big.Int
S() *big.Int
IsEthCompatible() bool
AsMessage(s Signer) (Message, error)
}
@ -412,6 +415,33 @@ func (tx *Transaction) Size() common.StorageSize {
return common.StorageSize(c)
}
// IsEthCompatible returns whether the txn is ethereum compatible
func (tx *Transaction) IsEthCompatible() bool {
return params.IsEthCompatible(tx.ChainID())
}
// ConvertToEth converts hmy txn to eth txn by removing the ShardID and ToShardID fields.
func (tx *Transaction) ConvertToEth() *EthTransaction {
var tx2 EthTransaction
d := &tx.data
d2 := &tx2.data
d2.AccountNonce = d.AccountNonce
d2.Price = new(big.Int).Set(d.Price)
d2.GasLimit = d.GasLimit
d2.Recipient = copyAddr(d.Recipient)
d2.Amount = new(big.Int).Set(d.Amount)
d2.Payload = append(d.Payload[:0:0], d.Payload...)
d2.V = new(big.Int).Set(d.V)
d2.R = new(big.Int).Set(d.R)
d2.S = new(big.Int).Set(d.S)
copy := tx2.Hash()
d2.Hash = &copy
return &tx2
}
// AsMessage returns the transaction as a core.Message.
//
// AsMessage requires a signer to derive the sender.
@ -515,9 +545,10 @@ func (s *TxByPrice) Pop() interface{} {
// transactions in a profit-maximizing sorted order, while supporting removing
// entire batches of transactions for non-executable accounts.
type TransactionsByPriceAndNonce struct {
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
heads TxByPrice // Next transaction for each unique account (price heap)
signer Signer // Signer for the set of transactions
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
heads TxByPrice // Next transaction for each unique account (price heap)
signer Signer // Signer for the set of transactions
ethSigner Signer // Signer for the set of transactions
}
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
@ -525,12 +556,16 @@ type TransactionsByPriceAndNonce struct {
//
// Note, the input map is reowned so the caller should not interact any more with
// if after providing it to the constructor.
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce {
func NewTransactionsByPriceAndNonce(hmySigner Signer, ethSigner Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce {
// Initialize a price based heap with the head transactions
heads := make(TxByPrice, 0, len(txs))
for from, accTxs := range txs {
heads = append(heads, accTxs[0])
// Ensure the sender address is from the signer
signer := hmySigner
if accTxs[0].IsEthCompatible() {
signer = ethSigner
}
acc, _ := Sender(signer, accTxs[0])
txs[acc] = accTxs[1:]
if from != acc {
@ -541,14 +576,15 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa
// Assemble and return the transaction set
return &TransactionsByPriceAndNonce{
txs: txs,
heads: heads,
signer: signer,
txs: txs,
heads: heads,
signer: hmySigner,
ethSigner: ethSigner,
}
}
// Peek returns the next transaction by price.
func (t *TransactionsByPriceAndNonce) Peek() InternalTransaction {
func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
if len(t.heads) == 0 {
return nil
}
@ -557,7 +593,11 @@ func (t *TransactionsByPriceAndNonce) Peek() InternalTransaction {
// Shift replaces the current best head with the next one from the same account.
func (t *TransactionsByPriceAndNonce) Shift() {
acc, _ := Sender(t.signer, t.heads[0])
signer := t.signer
if t.heads[0].IsEthCompatible() {
signer = t.ethSigner
}
acc, _ := Sender(signer, t.heads[0])
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)

@ -132,6 +132,7 @@ func (s EIP155Signer) Sender(tx InternalTransaction) (common.Address, error) {
if !tx.Protected() {
return HomesteadSigner{}.Sender(tx)
}
if tx.ChainID().Cmp(s.chainID) != 0 {
return common.Address{}, ErrInvalidChainID
}
@ -157,6 +158,18 @@ func (s EIP155Signer) SignatureValues(tx InternalTransaction, sig []byte) (R, S,
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s EIP155Signer) Hash(tx InternalTransaction) common.Hash {
if params.IsEthCompatible(s.chainID) {
// following the same logic as in go-eth implementation
return hash.FromRLP([]interface{}{
tx.Nonce(),
tx.GasPrice(),
tx.GasLimit(),
tx.To(),
tx.Value(),
tx.Data(),
s.chainID, uint(0), uint(0),
})
}
return hash.FromRLP([]interface{}{
tx.Nonce(),
tx.GasPrice(),

@ -53,7 +53,7 @@ func TestTransactionPriceNonceSort(t *testing.T) {
}
}
// Sort the transactions and cross check the nonce ordering
txset := NewTransactionsByPriceAndNonce(signer, groups)
txset := NewTransactionsByPriceAndNonce(signer, signer, groups)
txs := InternalTransactions{}
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {

@ -81,6 +81,7 @@ func enable1344(jt *JumpTable) {
// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// TODO: CHAINID - add fork (or a new opcode) to use ethereum compatible chainID
chainID := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID)
stack.push(chainID)
return nil, nil

@ -53,11 +53,12 @@ type Config struct {
func setDefaults(cfg *Config) {
if cfg.ChainConfig == nil {
cfg.ChainConfig = &params.ChainConfig{
ChainID: big.NewInt(1),
CrossTxEpoch: new(big.Int),
CrossLinkEpoch: new(big.Int),
EIP155Epoch: new(big.Int),
S3Epoch: new(big.Int),
ChainID: big.NewInt(1),
EthCompatibleChainID: params.EthMainnetChainID,
CrossTxEpoch: new(big.Int),
CrossLinkEpoch: new(big.Int),
EIP155Epoch: new(big.Int),
S3Epoch: new(big.Int),
}
}

@ -55,6 +55,8 @@ type Harmony struct {
NodeAPI NodeAPI
// ChainID is used to identify which network we are using
ChainID uint64
// EthCompatibleChainID is used to identify the Ethereum compatible chain ID
EthChainID uint64
// RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"`
ShardID uint32
@ -130,6 +132,7 @@ func New(
chainDb: chainDb,
NodeAPI: nodeAPI,
ChainID: nodeAPI.Blockchain().Config().ChainID.Uint64(),
EthChainID: nodeAPI.Blockchain().Config().EthCompatibleChainID.Uint64(),
ShardID: shardID,
leaderCache: leaderCache,
totalStakeCache: totalStakeCache,

@ -162,10 +162,15 @@ func (hmy *Harmony) TraceChain(ctx context.Context, start, end *types.Block, con
// Fetch and execute the next block trace tasks
for task := range tasks {
signer := types.MakeSigner(hmy.BlockChain.Config(), task.block.Number())
hmySigner := types.MakeSigner(hmy.BlockChain.Config(), task.block.Number())
ethSigner := types.NewEIP155Signer(hmy.BlockChain.Config().EthCompatibleChainID)
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
signer := hmySigner
if tx.IsEthCompatible() {
signer = ethSigner
}
msg, _ := tx.AsMessage(signer)
vmCtx := core.NewEVMContext(msg, task.block.Header(), hmy.BlockChain, nil)
@ -359,10 +364,10 @@ func (hmy *Harmony) TraceBlock(ctx context.Context, block *types.Block, config *
}
// Execute all the transaction contained within the block concurrently
var (
signer = types.MakeSigner(hmy.BlockChain.Config(), block.Number())
txs = block.Transactions()
results = make([]*TxTraceResult, len(txs))
hmySigner = types.MakeSigner(hmy.BlockChain.Config(), block.Number())
ethSigner = types.NewEIP155Signer(hmy.BlockChain.Config().EthCompatibleChainID)
txs = block.Transactions()
results = make([]*TxTraceResult, len(txs))
pend = new(sync.WaitGroup)
jobs = make(chan *txTraceTask, len(txs))
@ -378,6 +383,11 @@ func (hmy *Harmony) TraceBlock(ctx context.Context, block *types.Block, config *
// Fetch and execute the next transaction trace tasks
for task := range jobs {
signer := hmySigner
if txs[task.index].IsEthCompatible() {
signer = ethSigner
}
msg, _ := txs[task.index].AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), hmy.BlockChain, nil)
@ -396,6 +406,10 @@ func (hmy *Harmony) TraceBlock(ctx context.Context, block *types.Block, config *
// Send the trace task over for execution
jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
signer := hmySigner
if tx.IsEthCompatible() {
signer = ethSigner
}
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), hmy.BlockChain, nil)
@ -459,10 +473,15 @@ func (hmy *Harmony) standardTraceBlockToFile(ctx context.Context, block *types.B
// Execute transaction, either tracing all or just the requested one
var (
signer = types.MakeSigner(hmy.BlockChain.Config(), block.Number())
dumps []string
hmySigner = types.MakeSigner(hmy.BlockChain.Config(), block.Number())
ethSigner = types.NewEIP155Signer(hmy.BlockChain.Config().EthCompatibleChainID)
dumps []string
)
for i, tx := range block.Transactions() {
signer := hmySigner
if tx.IsEthCompatible() {
signer = ethSigner
}
// Prepare the transaction for un-traced execution
var (
msg, _ = tx.AsMessage(signer)
@ -685,9 +704,15 @@ func (hmy *Harmony) ComputeTxEnv(block *types.Block, txIndex int, reexec uint64)
}
// Recompute transactions up to the target index.
signer := types.MakeSigner(hmy.BlockChain.Config(), block.Number())
hmySigner := types.MakeSigner(hmy.BlockChain.Config(), block.Number())
ethSigner := types.NewEIP155Signer(hmy.BlockChain.Config().EthCompatibleChainID)
for idx, tx := range block.Transactions() {
signer := hmySigner
if tx.IsEthCompatible() {
signer = ethSigner
}
// Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), hmy.BlockChain, nil)

@ -3,6 +3,7 @@ package params
import (
"fmt"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
)
@ -16,154 +17,172 @@ var (
StressnetChainID = big.NewInt(5)
TestChainID = big.NewInt(99) // not a real network
AllProtocolChangesChainID = big.NewInt(100) // not a real network
// EthMainnetChainID to be reserved unique chain ID for eth compatible chains.
EthMainnetChainID = big.NewInt(1666600000)
EthTestnetChainID = big.NewInt(1666700000)
EthPangaeaChainID = big.NewInt(1666800000)
EthPartnerChainID = big.NewInt(1666900000)
EthStressnetChainID = big.NewInt(1661000000)
EthTestChainID = big.NewInt(1661100000) // not a real network
EthAllProtocolChangesChainID = big.NewInt(1661200000) // not a real network
)
// EpochTBD is a large, “not anytime soon” epoch. It used as a placeholder
// until the exact epoch is decided.
var EpochTBD = big.NewInt(10000000)
var once sync.Once
var (
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
ChainID: MainnetChainID,
CrossTxEpoch: big.NewInt(28),
CrossLinkEpoch: big.NewInt(186),
StakingEpoch: big.NewInt(186),
PreStakingEpoch: big.NewInt(185),
QuickUnlockEpoch: big.NewInt(191),
FiveSecondsEpoch: big.NewInt(230),
TwoSecondsEpoch: big.NewInt(366), // Around Tuesday Dec 8th 2020, 8AM PST
RedelegationEpoch: big.NewInt(290),
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
IstanbulEpoch: big.NewInt(314),
ReceiptLogEpoch: big.NewInt(101),
ChainID: MainnetChainID,
EthCompatibleChainID: EthMainnetChainID,
CrossTxEpoch: big.NewInt(28),
CrossLinkEpoch: big.NewInt(186),
StakingEpoch: big.NewInt(186),
PreStakingEpoch: big.NewInt(185),
QuickUnlockEpoch: big.NewInt(191),
FiveSecondsEpoch: big.NewInt(230),
TwoSecondsEpoch: big.NewInt(366), // Around Tuesday Dec 8th 2020, 8AM PST
RedelegationEpoch: big.NewInt(290),
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
IstanbulEpoch: big.NewInt(314),
ReceiptLogEpoch: big.NewInt(101),
}
// TestnetChainConfig contains the chain parameters to run a node on the harmony test network.
TestnetChainConfig = &ChainConfig{
ChainID: TestnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(16500),
TwoSecondsEpoch: big.NewInt(73000),
RedelegationEpoch: big.NewInt(36500),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(43800),
ReceiptLogEpoch: big.NewInt(0),
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(16500),
TwoSecondsEpoch: big.NewInt(73000),
RedelegationEpoch: big.NewInt(36500),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(43800),
ReceiptLogEpoch: big.NewInt(0),
}
// PangaeaChainConfig contains the chain parameters for the Pangaea network.
// All features except for CrossLink are enabled at launch.
PangaeaChainConfig = &ChainConfig{
ChainID: PangaeaChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
ChainID: PangaeaChainID,
EthCompatibleChainID: EthPangaeaChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
// PartnerChainConfig contains the chain parameters for the Partner network.
// All features except for CrossLink are enabled at launch.
PartnerChainConfig = &ChainConfig{
ChainID: PartnerChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
ChainID: PartnerChainID,
EthCompatibleChainID: EthPartnerChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
// StressnetChainConfig contains the chain parameters for the Stress test network.
// All features except for CrossLink are enabled at launch.
StressnetChainConfig = &ChainConfig{
ChainID: StressnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
ChainID: StressnetChainID,
EthCompatibleChainID: EthStressnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
// LocalnetChainConfig contains the chain parameters to run for local development.
LocalnetChainConfig = &ChainConfig{
ChainID: TestnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(0),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(3),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetChainID,
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(0),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(3),
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
// AllProtocolChanges ...
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllProtocolChanges = &ChainConfig{
AllProtocolChangesChainID, // ChainID
big.NewInt(0), // CrossTxEpoch
big.NewInt(0), // CrossLinkEpoch
big.NewInt(0), // StakingEpoch
big.NewInt(0), // PreStakingEpoch
big.NewInt(0), // QuickUnlockEpoch
big.NewInt(0), // FiveSecondsEpoch
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
AllProtocolChangesChainID, // ChainID
EthAllProtocolChangesChainID, // EthCompatibleChainID
big.NewInt(0), // CrossTxEpoch
big.NewInt(0), // CrossLinkEpoch
big.NewInt(0), // StakingEpoch
big.NewInt(0), // PreStakingEpoch
big.NewInt(0), // QuickUnlockEpoch
big.NewInt(0), // FiveSecondsEpoch
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
}
// TestChainConfig ...
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
TestChainConfig = &ChainConfig{
TestChainID, // ChainID
big.NewInt(0), // CrossTxEpoch
big.NewInt(0), // CrossLinkEpoch
big.NewInt(0), // StakingEpoch
big.NewInt(0), // PreStakingEpoch
big.NewInt(0), // QuickUnlockEpoch
big.NewInt(0), // FiveSecondsEpoch
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
TestChainID, // ChainID
EthTestChainID, // EthCompatibleChainID
big.NewInt(0), // CrossTxEpoch
big.NewInt(0), // CrossLinkEpoch
big.NewInt(0), // StakingEpoch
big.NewInt(0), // PreStakingEpoch
big.NewInt(0), // QuickUnlockEpoch
big.NewInt(0), // FiveSecondsEpoch
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
}
// TestRules ...
@ -191,6 +210,9 @@ type ChainConfig struct {
// ChainId identifies the current chain and is used for replay protection
ChainID *big.Int `json:"chain-id"`
// EthCompatibleChainID identifies the chain id used for ethereum compatible transactions
EthCompatibleChainID *big.Int `json:"eth-compatible-chain-id"`
// CrossTxEpoch is the epoch where cross-shard transaction starts being
// processed.
CrossTxEpoch *big.Int `json:"cross-tx-epoch,omitempty"`
@ -235,8 +257,9 @@ type ChainConfig struct {
// String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string {
return fmt.Sprintf("{ChainID: %v EIP155: %v CrossTx: %v Staking: %v CrossLink: %v ReceiptLog: %v}",
return fmt.Sprintf("{ChainID: %v EthCompatibleChainID: %v EIP155: %v CrossTx: %v Staking: %v CrossLink: %v ReceiptLog: %v}",
c.ChainID,
c.EthCompatibleChainID,
c.EIP155Epoch,
c.CrossTxEpoch,
c.StakingEpoch,
@ -320,6 +343,25 @@ func (c *ChainConfig) IsReceiptLog(epoch *big.Int) bool {
return isForked(c.ReceiptLogEpoch, epoch)
}
// UpdateEthChainIDByShard update the ethChainID based on shard ID.
func UpdateEthChainIDByShard(shardID uint32) {
once.Do(func() {
MainnetChainConfig.EthCompatibleChainID.Add(MainnetChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
TestnetChainConfig.EthCompatibleChainID.Add(TestnetChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
PangaeaChainConfig.EthCompatibleChainID.Add(PangaeaChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
PartnerChainConfig.EthCompatibleChainID.Add(PartnerChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
StressnetChainConfig.EthCompatibleChainID.Add(StressnetChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
LocalnetChainConfig.EthCompatibleChainID.Add(LocalnetChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
AllProtocolChanges.EthCompatibleChainID.Add(AllProtocolChanges.EthCompatibleChainID, big.NewInt(int64(shardID)))
TestChainConfig.EthCompatibleChainID.Add(TestChainConfig.EthCompatibleChainID, big.NewInt(int64(shardID)))
})
}
// IsEthCompatible returns whether the chainID is for ethereum compatible txn or not
func IsEthCompatible(chainID *big.Int) bool {
return chainID.Cmp(EthMainnetChainID) >= 0
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
@ -350,6 +392,7 @@ func isForked(s, epoch *big.Int) bool {
// phases.
type Rules struct {
ChainID *big.Int
EthChainID *big.Int
IsCrossLink, IsEIP155, IsS3, IsReceiptLog, IsIstanbul bool
}
@ -359,8 +402,13 @@ func (c *ChainConfig) Rules(epoch *big.Int) Rules {
if chainID == nil {
chainID = new(big.Int)
}
ethChainID := c.EthCompatibleChainID
if ethChainID == nil {
ethChainID = new(big.Int)
}
return Rules{
ChainID: new(big.Int).Set(chainID),
EthChainID: new(big.Int).Set(ethChainID),
IsCrossLink: c.IsCrossLink(epoch),
IsEIP155: c.IsEIP155(epoch),
IsS3: c.IsS3(epoch),

@ -34,6 +34,7 @@ import (
// environment is the worker's current environment and holds all of the current state information.
type environment struct {
signer types.Signer
ethSigner types.Signer
state *state.DB // apply state changes here
gasPool *core.GasPool // available gas used to pack transactions
header *block.Header
@ -76,7 +77,11 @@ func (w *Worker) CommitSortedTransactions(
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
// We use the eip155 signer regardless of the current hf.
from, _ := types.Sender(w.current.signer, tx)
signer := w.current.signer
if tx.IsEthCompatible() {
signer = w.current.ethSigner
}
from, _ := types.Sender(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() && !w.config.IsEIP155(w.current.header.Epoch()) {
@ -92,7 +97,7 @@ func (w *Worker) CommitSortedTransactions(
// Start executing the transaction
w.current.state.Prepare(tx.Hash(), common.Hash{}, len(w.current.txs))
_, err := w.commitTransaction(tx.(*types.Transaction), coinbase)
_, err := w.commitTransaction(tx, coinbase)
sender, _ := common2.AddressToBech32(from)
switch err {
@ -134,7 +139,7 @@ func (w *Worker) CommitTransactions(
}
// HARMONY TXNS
normalTxns := types.NewTransactionsByPriceAndNonce(w.current.signer, pendingNormal)
normalTxns := types.NewTransactionsByPriceAndNonce(w.current.signer, w.current.ethSigner, pendingNormal)
w.CommitSortedTransactions(normalTxns, coinbase)
// STAKING - only beaconchain process staking transaction
@ -300,9 +305,10 @@ func (w *Worker) makeCurrent(parent *types.Block, header *block.Header) error {
return err
}
env := &environment{
signer: types.NewEIP155Signer(w.config.ChainID),
state: state,
header: header,
signer: types.NewEIP155Signer(w.config.ChainID),
ethSigner: types.NewEIP155Signer(w.config.EthCompatibleChainID),
state: state,
header: header,
}
w.current = env

@ -259,6 +259,11 @@ func (tx *StakingTransaction) Size() common.StorageSize {
return common.StorageSize(c)
}
// IsEthCompatible returns whether the txn is ethereum compatible
func (tx *StakingTransaction) IsEthCompatible() bool {
return false
}
type writeCounter common.StorageSize
func (c *writeCounter) Write(b []byte) (int, error) {

Loading…
Cancel
Save