Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to pre-EIP155 txs #1582

Merged
merged 8 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/e2e-group1/preEIP155_test.go
3 changes: 2 additions & 1 deletion pool/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ func (p *Pool) IsTxPending(ctx context.Context, hash common.Hash) (bool, error)

func (p *Pool) validateTx(ctx context.Context, tx types.Transaction) error {
// check chain id
if tx.ChainId().Uint64() != p.chainID {
txChainID := tx.ChainId().Uint64()
if txChainID != p.chainID && txChainID != 0 {
return ErrInvalidChainID
}

Expand Down
92 changes: 92 additions & 0 deletions pool/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,98 @@ func Test_AddTx(t *testing.T) {
assert.Equal(t, 1, c, "invalid number of txs in the pool")
}

func Test_AddPreEIP155Tx(t *testing.T) {
initOrResetDB()

stateSqlDB, err := db.NewSQLDB(stateDBCfg)
if err != nil {
panic(err)
}
defer stateSqlDB.Close() //nolint:gosec,errcheck

poolSqlDB, err := db.NewSQLDB(poolDBCfg)
if err != nil {
t.Error(err)
}
defer poolSqlDB.Close() //nolint:gosec,errcheck

st := newState(stateSqlDB)

genesisBlock := state.Block{
BlockNumber: 0,
BlockHash: state.ZeroHash,
ParentHash: state.ZeroHash,
ReceivedAt: time.Now(),
}
genesis := state.Genesis{
Actions: []*state.GenesisAction{
{
Address: "0xb48cA794d49EeC406A5dD2c547717e37b5952a83",
Type: int(merkletree.LeafTypeBalance),
Value: "1000000000000000000000",
},
{
Address: "0x4d5Cf5032B2a844602278b01199ED191A86c93ff",
Type: int(merkletree.LeafTypeBalance),
Value: "200000000000000000000",
},
},
}
ctx := context.Background()
dbTx, err := st.BeginStateTransaction(ctx)
require.NoError(t, err)
_, err = st.SetGenesis(ctx, genesisBlock, genesis, dbTx)
require.NoError(t, err)
require.NoError(t, dbTx.Commit(ctx))

s, err := pgpoolstorage.NewPostgresPoolStorage(poolDBCfg)
if err != nil {
t.Error(err)
}

const chainID = 2576980377
cfg := pool.Config{
FreeClaimGasLimit: 150000,
}
p := pool.NewPool(cfg, s, st, common.Address{}, chainID)

batchL2Data := "0xe580843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae98808464fbb77c6b39bdc5f8e458aba689f2a1ff8c543a94e4817bda40f3fe34080c4ab26c1e3c2fc2cda93bc32f0a79940501fd505dcf48d94abfde932ebf1417f502cb0d9de81b"
b, err := hex.DecodeHex(batchL2Data)
require.NoError(t, err)
txs, _, err := state.DecodeTxs(b)
require.NoError(t, err)

tx := txs[0]

err = p.AddTx(ctx, tx)
require.NoError(t, err)

rows, err := poolSqlDB.Query(ctx, "SELECT hash, encoded, decoded, status FROM pool.txs")
defer rows.Close() // nolint:staticcheck
require.NoError(t, err)

c := 0
for rows.Next() {
var hash, encoded, decoded, status string
err := rows.Scan(&hash, &encoded, &decoded, &status)
require.NoError(t, err)

b, err := tx.MarshalBinary()
require.NoError(t, err)

bJSON, err := tx.MarshalJSON()
require.NoError(t, err)

assert.Equal(t, tx.Hash().String(), hash, "invalid hash")
assert.Equal(t, hex.EncodeToHex(b), encoded, "invalid encoded")
assert.JSONEq(t, string(bJSON), decoded, "invalid decoded")
assert.Equal(t, string(pool.TxStatusPending), status, "invalid tx status")
c++
}

assert.Equal(t, 1, c, "invalid number of txs in the pool")
}

func Test_GetPendingTxs(t *testing.T) {
initOrResetDB()

Expand Down
7 changes: 5 additions & 2 deletions state/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ var (
func CheckSignature(tx types.Transaction) error {
// Check Signature
v, r, s := tx.RawSignatureValues()
plainV := byte(v.Uint64() - 35 - 2*(tx.ChainId().Uint64()))

plainV := byte(0)
chainID := tx.ChainId().Uint64()
if chainID != 0 {
plainV = byte(v.Uint64() - 35 - 2*(chainID))
}
if !crypto.ValidateSignatureValues(plainV, r, s, false) {
return ErrInvalidSig
}
Expand Down
55 changes: 38 additions & 17 deletions state/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

const ether155V = 27
const (
double = 2
ether155V = 27
etherPre155V = 35
)

// EncodeTransactions RLP encodes the given transactions.
func EncodeTransactions(txs []types.Transaction) ([]byte, error) {
Expand All @@ -25,15 +29,22 @@ func EncodeTransactions(txs []types.Transaction) ([]byte, error) {
nonce, gasPrice, gas, to, value, data, chainID := tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.ChainId()
log.Debug(nonce, " ", gasPrice, " ", gas, " ", to, " ", value, " ", len(data), " ", chainID)

txCodedRlp, err := rlp.EncodeToBytes([]interface{}{
rlpFieldsToEncode := []interface{}{
nonce,
gasPrice,
gas,
to,
value,
data,
chainID, uint(0), uint(0),
})
}

if tx.ChainId().Uint64() > 0 {
rlpFieldsToEncode = append(rlpFieldsToEncode, chainID)
rlpFieldsToEncode = append(rlpFieldsToEncode, uint(0))
rlpFieldsToEncode = append(rlpFieldsToEncode, uint(0))
}

txCodedRlp, err := rlp.EncodeToBytes(rlpFieldsToEncode)

if err != nil {
return nil, err
Expand Down Expand Up @@ -91,7 +102,7 @@ func EncodeUnsignedTransaction(tx types.Transaction, chainID uint64) ([]byte, er
return txData, nil
}

// DecodeTxs extracts Tansactions for its encoded form
// DecodeTxs extracts Transactions for its encoded form
func DecodeTxs(txsData []byte) ([]types.Transaction, []byte, error) {
// Process coded txs
var pos int64
Expand All @@ -105,7 +116,6 @@ func DecodeTxs(txsData []byte) ([]types.Transaction, []byte, error) {
ff = 255 // max value of rlp header
shortRlp = 55 // length of the short rlp codification
f7 = 247 // 192 + 55 = c0 + shortRlp
etherNewV = 35
mul2 = 2
)
txDataLength := len(txsData)
Expand All @@ -132,26 +142,37 @@ func DecodeTxs(txsData []byte) ([]types.Transaction, []byte, error) {

fullDataTx := txsData[pos : pos+len+rLength+sLength+vLength+headerByteLength]
txInfo := txsData[pos : pos+len+headerByteLength]
r := txsData[pos+len+headerByteLength : pos+len+rLength+headerByteLength]
s := txsData[pos+len+rLength+headerByteLength : pos+len+rLength+sLength+headerByteLength]
v := txsData[pos+len+rLength+sLength+headerByteLength : pos+len+rLength+sLength+vLength+headerByteLength]
rData := txsData[pos+len+headerByteLength : pos+len+rLength+headerByteLength]
sData := txsData[pos+len+rLength+headerByteLength : pos+len+rLength+sLength+headerByteLength]
vData := txsData[pos+len+rLength+sLength+headerByteLength : pos+len+rLength+sLength+vLength+headerByteLength]

pos = pos + len + rLength + sLength + vLength + headerByteLength

// Decode tx
var tx types.LegacyTx
err = rlp.DecodeBytes(txInfo, &tx)
// Decode rlpFields
var rlpFields [][]byte
err = rlp.DecodeBytes(txInfo, &rlpFields)
if err != nil {
log.Debug("error decoding tx bytes: ", err, ". fullDataTx: ", hex.EncodeToString(fullDataTx), "\n tx: ", hex.EncodeToString(txInfo), "\n Txs received: ", hex.EncodeToString(txsData))
return []types.Transaction{}, []byte{}, err
}

//tx.V = v-27+chainId*2+35
tx.V = new(big.Int).Add(new(big.Int).Sub(new(big.Int).SetBytes(v), big.NewInt(ether155V)), new(big.Int).Add(new(big.Int).Mul(tx.V, big.NewInt(mul2)), big.NewInt(etherNewV)))
tx.R = new(big.Int).SetBytes(r)
tx.S = new(big.Int).SetBytes(s)
legacyTx, chainID, err := RlpFieldsToLegacyTx(rlpFields)
if err != nil {
log.Debug("error creating tx from rlp fields: ", err, ". fullDataTx: ", hex.EncodeToString(fullDataTx), "\n tx: ", hex.EncodeToString(txInfo), "\n Txs received: ", hex.EncodeToString(txsData))
return []types.Transaction{}, []byte{}, err
}

if chainID != nil {
//v = v-27+chainId*2+35
legacyTx.V = new(big.Int).Add(new(big.Int).Sub(new(big.Int).SetBytes(vData), big.NewInt(ether155V)), new(big.Int).Add(new(big.Int).Mul(chainID, big.NewInt(mul2)), big.NewInt(etherPre155V)))
} else {
legacyTx.V = new(big.Int).SetBytes(vData)
}
legacyTx.R = new(big.Int).SetBytes(rData)
legacyTx.S = new(big.Int).SetBytes(sData)

txs = append(txs, *types.NewTx(&tx))
tx := types.NewTx(legacyTx)
txs = append(txs, *tx)
}
return txs, txsData, nil
}
Expand Down
70 changes: 70 additions & 0 deletions state/transaction.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package state

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
Expand All @@ -14,3 +16,71 @@ func GetSender(tx types.Transaction) (common.Address, error) {
}
return sender, nil
}

// RlpFieldsToLegacyTx parses the rlp fields slice into a type.LegacyTx
// in this specific order:
//
// required fields:
// [0] Nonce uint64
// [1] GasPrice *big.Int
// [2] Gas uint64
// [3] To *common.Address
// [4] Value *big.Int
// [5] Data []byte
//
// optional fields:
// [6] V *big.Int
// [7] R *big.Int
// [8] S *big.Int
func RlpFieldsToLegacyTx(fields [][]byte) (tx *types.LegacyTx, chainID *big.Int, err error) {
const (
fieldsSizeWithoutChainID = 6
fieldsSizeWithV = 7
fieldsSizeWithVR = 8
fieldsSizeWithVRS = 9
)

if len(fields) != fieldsSizeWithoutChainID && len(fields) != fieldsSizeWithV && len(fields) != fieldsSizeWithVRS {
return nil, nil, types.ErrTxTypeNotSupported
}

nonce := big.NewInt(0).SetBytes(fields[0]).Uint64()
gasPrice := big.NewInt(0).SetBytes(fields[1])
gas := big.NewInt(0).SetBytes(fields[2]).Uint64()
var to *common.Address
if fields[3] != nil {
tmp := common.BytesToAddress(fields[3])
to = &tmp
}
value := big.NewInt(0).SetBytes(fields[4])
data := fields[5]

v := big.NewInt(0)
if len(fields) >= fieldsSizeWithV {
v = big.NewInt(0).SetBytes(fields[6])
chainID = big.NewInt(0).Sub(v, big.NewInt(0).SetUint64(etherPre155V))
chainID = big.NewInt(0).Quo(chainID, big.NewInt(double))
}

r := big.NewInt(0)
if len(fields) >= fieldsSizeWithVR {
r = big.NewInt(0).SetBytes(fields[7])
}

s := big.NewInt(0)
if len(fields) >= fieldsSizeWithVRS {
s = big.NewInt(0).SetBytes(fields[8])
}

return &types.LegacyTx{
Nonce: nonce,
GasPrice: gasPrice,
Gas: gas,
To: to,
Value: value,
Data: data,
V: v,
R: r,
S: s,
}, chainID, nil
}
2 changes: 1 addition & 1 deletion test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ services:
ports:
- 8545:8545
- 8546:8546
command: ["--http", "--http.api", "admin,eth,debug,miner,net,txpool,personal,web3", "--http.addr", "0.0.0.0","--http.corsdomain", "*", "--http.vhosts" ,"*", "--ws", "--ws.origins", "*", "--ws.addr", "0.0.0.0", "--dev", "--datadir", "/geth_data", "--syncmode", "full"]
command: ["--http", "--http.api", "admin,eth,debug,miner,net,txpool,personal,web3", "--http.addr", "0.0.0.0","--http.corsdomain", "*", "--http.vhosts" ,"*", "--ws", "--ws.origins", "*", "--ws.addr", "0.0.0.0", "--dev", "--datadir", "/geth_data", "--syncmode", "full", "--rpc.allow-unprotected-txs"]

zkevm-prover:
container_name: zkevm-prover
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package e2e

import "testing"

func TestDebugTraceTransaction(t *testing.T) {

}
Loading