2021-06-19 22:41:15 +00:00
|
|
|
/*
|
|
|
|
Copyright 2021 Erigon contributors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package txpool
|
|
|
|
|
|
|
|
import (
|
2021-06-24 23:16:36 +00:00
|
|
|
"encoding/binary"
|
2021-06-19 22:41:15 +00:00
|
|
|
"fmt"
|
2021-06-24 23:16:36 +00:00
|
|
|
"hash"
|
2021-07-30 09:24:20 +00:00
|
|
|
"io"
|
2021-06-24 23:16:36 +00:00
|
|
|
"math/bits"
|
2021-06-19 22:41:15 +00:00
|
|
|
|
|
|
|
"github.com/holiman/uint256"
|
2021-07-25 12:19:33 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/types"
|
2021-07-27 05:03:59 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/rlp"
|
2021-06-26 11:55:32 +00:00
|
|
|
"github.com/ledgerwatch/secp256k1"
|
2021-06-24 16:35:12 +00:00
|
|
|
"golang.org/x/crypto/sha3"
|
2021-06-19 22:41:15 +00:00
|
|
|
)
|
|
|
|
|
2021-07-25 12:19:33 +00:00
|
|
|
type PeerID *types.H512
|
|
|
|
|
2021-07-26 00:57:49 +00:00
|
|
|
type Hashes []byte // flatten list of 32-byte hashes
|
|
|
|
|
2021-06-24 23:16:36 +00:00
|
|
|
// TxContext is object that is required to parse transactions and turn transaction payload into TxSlot objects
|
|
|
|
// usage of TxContext helps avoid extra memory allocations
|
|
|
|
type TxParseContext struct {
|
2021-07-27 05:03:59 +00:00
|
|
|
recCtx *secp256k1.Context // Context for sender recovery
|
2021-06-24 23:16:36 +00:00
|
|
|
keccak1 hash.Hash
|
|
|
|
keccak2 hash.Hash
|
2021-06-26 10:18:39 +00:00
|
|
|
chainId, r, s uint256.Int // Signature values
|
2021-06-24 23:16:36 +00:00
|
|
|
n27, n28, n35 uint256.Int
|
2021-06-26 11:55:32 +00:00
|
|
|
buf [65]byte // buffer needs to be enough for hashes (32 bytes) and for public key (65 bytes)
|
2021-06-24 23:16:36 +00:00
|
|
|
sighash [32]byte
|
|
|
|
sig [65]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTxParseContext() *TxParseContext {
|
|
|
|
ctx := &TxParseContext{
|
|
|
|
keccak1: sha3.NewLegacyKeccak256(),
|
|
|
|
keccak2: sha3.NewLegacyKeccak256(),
|
2021-06-26 11:55:32 +00:00
|
|
|
recCtx: secp256k1.NewContext(),
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
ctx.n27.SetUint64(27)
|
|
|
|
ctx.n28.SetUint64(28)
|
|
|
|
ctx.n35.SetUint64(35)
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
|
2021-06-19 22:41:15 +00:00
|
|
|
// TxSlot contains information extracted from an Ethereum transaction, which is enough to manage it inside the transaction.
|
|
|
|
// Also, it contains some auxillary information, like ephemeral fields, and indices within priority queues
|
|
|
|
type TxSlot struct {
|
2021-06-30 12:34:27 +00:00
|
|
|
//txId uint64 // Transaction id (distinct from transaction hash), used as a compact reference to a transaction accross data structures
|
|
|
|
//senderId uint64 // Sender id (distinct from sender address), used as a compact referecne to to a sender accross data structures
|
2021-06-19 22:41:15 +00:00
|
|
|
nonce uint64 // Nonce of the transaction
|
|
|
|
tip uint64 // Maximum tip that transaction is giving to miner/block proposer
|
|
|
|
feeCap uint64 // Maximum fee that transaction burns and gives to the miner/block proposer
|
|
|
|
gas uint64 // Gas limit of the transaction
|
|
|
|
value uint256.Int // Value transferred by the transaction
|
2021-07-27 05:03:59 +00:00
|
|
|
idHash [32]byte // Transaction hash for the purposes of using it as a transaction Id
|
2021-07-31 08:10:42 +00:00
|
|
|
senderID uint64 // SenderID - require external mapping to it's address
|
2021-06-19 22:41:15 +00:00
|
|
|
creation bool // Set to true if "To" field of the transation is not set
|
|
|
|
dataLen int // Length of transaction's data (for calculation of intrinsic gas)
|
|
|
|
alAddrCount int // Number of addresses in the access list
|
|
|
|
alStorCount int // Number of storage keys in the access list
|
2021-06-30 12:34:27 +00:00
|
|
|
//bestIdx int // Index of the transaction in the best priority queue (of whatever pool it currently belongs to)
|
|
|
|
//worstIdx int // Index of the transaction in the worst priority queue (of whatever pook it currently belongs to)
|
|
|
|
//local bool // Whether transaction has been injected locally (and hence needs priority when mining or proposing a block)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
LegacyTxType int = 0
|
|
|
|
AccessListTxType int = 1
|
|
|
|
DynamicFeeTxType int = 2
|
|
|
|
)
|
|
|
|
|
2021-07-15 11:00:14 +00:00
|
|
|
const ParseTransactionErrorPrefix = "parse transaction payload"
|
|
|
|
|
2021-06-19 22:41:15 +00:00
|
|
|
// ParseTransaction extracts all the information from the transactions's payload (RLP) necessary to build TxSlot
|
|
|
|
// it also performs syntactic validation of the transactions
|
2021-07-31 08:10:42 +00:00
|
|
|
func (ctx *TxParseContext) ParseTransaction(payload []byte, pos int) (slot *TxSlot, sender [20]byte, p int, err error) {
|
2021-06-19 22:41:15 +00:00
|
|
|
if len(payload) == 0 {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: empty rlp", ParseTransactionErrorPrefix)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-07-31 09:29:29 +00:00
|
|
|
slot = &TxSlot{}
|
2021-06-24 16:35:12 +00:00
|
|
|
// Compute transaction hash
|
2021-06-24 23:16:36 +00:00
|
|
|
ctx.keccak1.Reset()
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.keccak2.Reset()
|
2021-07-27 08:47:33 +00:00
|
|
|
// Legacy transations have list Prefix, whereas EIP-2718 transactions have string Prefix
|
|
|
|
// therefore we assign the first returned value of Prefix function (list) to legacy variable
|
|
|
|
dataPos, dataLen, legacy, err := rlp.Prefix(payload, pos)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: size Prefix: %v", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-07-27 05:18:40 +00:00
|
|
|
if dataPos+dataLen != len(payload) {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: transaction must be either 1 list or 1 string", ParseTransactionErrorPrefix)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-07-31 08:10:42 +00:00
|
|
|
p = dataPos
|
2021-06-19 22:41:15 +00:00
|
|
|
|
|
|
|
var txType int
|
2021-06-22 12:53:02 +00:00
|
|
|
// If it is non-legacy transaction, the transaction type follows, and then the the list
|
2021-06-19 22:41:15 +00:00
|
|
|
if !legacy {
|
2021-06-24 16:35:12 +00:00
|
|
|
txType = int(payload[p])
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err = ctx.keccak1.Write(payload[p : p+1]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing idHash (hashing type Prefix): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 16:35:12 +00:00
|
|
|
}
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err = ctx.keccak2.Write(payload[p : p+1]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing type Prefix): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
p++
|
2021-07-27 05:18:40 +00:00
|
|
|
if p >= len(payload) {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: unexpected end of payload after txType", ParseTransactionErrorPrefix)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-07-27 06:06:38 +00:00
|
|
|
dataPos, dataLen, err = rlp.List(payload, p)
|
2021-06-22 12:53:02 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: envelope Prefix: %v", ParseTransactionErrorPrefix, err)
|
2021-06-22 12:53:02 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
// Hash the envelope, not the full payload
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err = ctx.keccak1.Write(payload[p : dataPos+dataLen]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing idHash (hashing the envelope): %w", ParseTransactionErrorPrefix, err)
|
2021-06-22 12:53:02 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
p = dataPos
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-24 23:16:36 +00:00
|
|
|
// Remember where signing hash data begins (it will need to be wrapped in an RLP list)
|
|
|
|
sigHashPos := p
|
2021-06-19 22:41:15 +00:00
|
|
|
// If it is non-legacy tx, chainId follows, but we skip it
|
|
|
|
if !legacy {
|
2021-07-27 06:06:38 +00:00
|
|
|
dataPos, dataLen, err = rlp.String(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: chainId len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
p = dataPos + dataLen
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Next follows the nonce, which we need to parse
|
2021-07-27 05:18:40 +00:00
|
|
|
p, slot.nonce, err = rlp.U64(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: nonce: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Next follows gas price or tip
|
|
|
|
// Although consensus rules specify that tip can be up to 256 bit long, we narrow it to 64 bit
|
2021-07-27 05:18:40 +00:00
|
|
|
p, slot.tip, err = rlp.U64(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: tip: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Next follows feeCap, but only for dynamic fee transactions, for legacy transaction, it is
|
|
|
|
// equal to tip
|
|
|
|
if txType < DynamicFeeTxType {
|
|
|
|
slot.feeCap = slot.tip
|
|
|
|
} else {
|
|
|
|
// Although consensus rules specify that feeCap can be up to 256 bit long, we narrow it to 64 bit
|
2021-07-27 05:18:40 +00:00
|
|
|
p, slot.feeCap, err = rlp.U64(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: feeCap: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Next follows gas
|
2021-07-27 05:18:40 +00:00
|
|
|
p, slot.gas, err = rlp.U64(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: gas: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Next follows the destrination address (if present)
|
2021-07-27 06:06:38 +00:00
|
|
|
dataPos, dataLen, err = rlp.String(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: to len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
if dataLen != 0 && dataLen != 20 {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: unexpected length of to field: %d", ParseTransactionErrorPrefix, dataLen)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Only note if To field is empty or not
|
|
|
|
slot.creation = dataLen == 0
|
2021-06-24 16:35:12 +00:00
|
|
|
p = dataPos + dataLen
|
2021-06-19 22:41:15 +00:00
|
|
|
// Next follows value
|
2021-07-27 05:18:40 +00:00
|
|
|
p, err = rlp.U256(payload, p, &slot.value)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: value: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
// Next goes data, but we are only interesting in its length
|
2021-07-27 06:06:38 +00:00
|
|
|
dataPos, dataLen, err = rlp.String(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: data len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
|
|
|
slot.dataLen = dataLen
|
2021-06-24 16:35:12 +00:00
|
|
|
p = dataPos + dataLen
|
2021-06-19 22:41:15 +00:00
|
|
|
// Next follows access list for non-legacy transactions, we are only interesting in number of addresses and storage keys
|
2021-06-22 12:53:02 +00:00
|
|
|
if !legacy {
|
2021-07-27 06:06:38 +00:00
|
|
|
dataPos, dataLen, err = rlp.List(payload, p)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: access list len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-22 12:53:02 +00:00
|
|
|
tuplePos := dataPos
|
|
|
|
var tupleLen int
|
|
|
|
for tuplePos < dataPos+dataLen {
|
2021-07-27 06:06:38 +00:00
|
|
|
tuplePos, tupleLen, err = rlp.List(payload, tuplePos)
|
2021-06-19 22:41:15 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: tuple len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-22 12:53:02 +00:00
|
|
|
}
|
2021-07-27 06:06:38 +00:00
|
|
|
var addrPos int
|
|
|
|
addrPos, err = rlp.StringOfLen(payload, tuplePos, 20)
|
2021-06-22 12:53:02 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: tuple addr len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-22 12:53:02 +00:00
|
|
|
slot.alAddrCount++
|
2021-06-24 16:35:12 +00:00
|
|
|
var storagePos, storageLen int
|
2021-07-27 06:06:38 +00:00
|
|
|
storagePos, storageLen, err = rlp.List(payload, addrPos+20)
|
2021-06-24 16:35:12 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: storage key list len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 16:35:12 +00:00
|
|
|
}
|
|
|
|
skeyPos := storagePos
|
|
|
|
for skeyPos < storagePos+storageLen {
|
2021-07-27 06:06:38 +00:00
|
|
|
skeyPos, err = rlp.StringOfLen(payload, skeyPos, 32)
|
2021-06-22 12:53:02 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: tuple storage key len: %w", ParseTransactionErrorPrefix, err)
|
2021-06-22 12:53:02 +00:00
|
|
|
}
|
|
|
|
slot.alStorCount++
|
2021-07-27 06:06:38 +00:00
|
|
|
skeyPos += 32
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
if skeyPos != storagePos+storageLen {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: extraneous space in the tuple after storage key list", ParseTransactionErrorPrefix)
|
2021-06-24 16:35:12 +00:00
|
|
|
}
|
2021-07-27 06:06:38 +00:00
|
|
|
tuplePos += tupleLen
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
if tuplePos != dataPos+dataLen {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: extraneous space in the access list after all tuples", ParseTransactionErrorPrefix)
|
2021-06-24 16:35:12 +00:00
|
|
|
}
|
|
|
|
p = dataPos + dataLen
|
2021-06-23 16:45:44 +00:00
|
|
|
}
|
2021-06-24 23:16:36 +00:00
|
|
|
// This is where the data for sighash ends
|
2021-06-23 16:45:44 +00:00
|
|
|
// Next follows V of the signature
|
2021-06-24 23:16:36 +00:00
|
|
|
var vByte byte
|
|
|
|
sigHashEnd := p
|
|
|
|
sigHashLen := uint(sigHashEnd - sigHashPos)
|
|
|
|
var chainIdBits, chainIdLen int
|
|
|
|
if legacy {
|
2021-07-27 05:18:40 +00:00
|
|
|
p, err = rlp.U256(payload, p, &ctx.chainId)
|
2021-06-24 23:16:36 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: V: %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
// Compute chainId from V
|
2021-06-26 10:18:39 +00:00
|
|
|
if ctx.chainId.Eq(&ctx.n27) || ctx.chainId.Eq(&ctx.n28) {
|
|
|
|
// Do not add chain id and two extra zeros
|
2021-06-26 11:55:32 +00:00
|
|
|
vByte = byte(ctx.chainId.Uint64() - 27)
|
2021-06-24 23:16:36 +00:00
|
|
|
} else {
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.chainId.Sub(&ctx.chainId, &ctx.n35)
|
2021-06-26 11:55:32 +00:00
|
|
|
vByte = byte(1 - (ctx.chainId.Uint64() & 1))
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.chainId.Rsh(&ctx.chainId, 1)
|
|
|
|
chainIdBits = ctx.chainId.BitLen()
|
2021-06-24 23:16:36 +00:00
|
|
|
if chainIdBits <= 7 {
|
|
|
|
chainIdLen = 1
|
|
|
|
} else {
|
|
|
|
chainIdLen = (chainIdBits + 7) / 8 // It is always < 56 bytes
|
2021-07-27 08:47:33 +00:00
|
|
|
sigHashLen++ // For chainId len Prefix
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
sigHashLen += uint(chainIdLen) // For chainId
|
2021-06-26 10:18:39 +00:00
|
|
|
sigHashLen += 2 // For two extra zeros
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var v uint64
|
2021-07-27 05:18:40 +00:00
|
|
|
p, v, err = rlp.U64(payload, p)
|
2021-06-24 23:16:36 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: V: %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
if v > 1 {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: V is loo large: %d", ParseTransactionErrorPrefix, v)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
vByte = byte(v)
|
2021-06-23 16:45:44 +00:00
|
|
|
}
|
|
|
|
// Next follows R of the signature
|
2021-07-27 05:18:40 +00:00
|
|
|
p, err = rlp.U256(payload, p, &ctx.r)
|
2021-06-23 16:45:44 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: R: %w", ParseTransactionErrorPrefix, err)
|
2021-06-23 16:45:44 +00:00
|
|
|
}
|
|
|
|
// New follows S of the signature
|
2021-07-27 05:18:40 +00:00
|
|
|
p, err = rlp.U256(payload, p, &ctx.s)
|
2021-06-23 16:45:44 +00:00
|
|
|
if err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: S: %w", ParseTransactionErrorPrefix, err)
|
2021-06-23 16:45:44 +00:00
|
|
|
}
|
2021-06-24 16:35:12 +00:00
|
|
|
// For legacy transactions, hash the full payload
|
|
|
|
if legacy {
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err = ctx.keccak1.Write(payload[pos:p]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing idHash: %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 16:35:12 +00:00
|
|
|
}
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|
2021-07-30 09:24:20 +00:00
|
|
|
//ctx.keccak1.Sum(slot.idHash[:0])
|
|
|
|
_, _ = ctx.keccak1.(io.Reader).Read(slot.idHash[:32])
|
2021-06-24 23:16:36 +00:00
|
|
|
// Computing sigHash (hash used to recover sender from the signature)
|
2021-07-27 08:47:33 +00:00
|
|
|
// Write len Prefix to the sighash
|
2021-06-24 23:16:36 +00:00
|
|
|
if sigHashLen < 56 {
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.buf[0] = byte(sigHashLen) + 192
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err := ctx.keccak2.Write(ctx.buf[:1]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing len Prefix): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
beLen := (bits.Len(uint(sigHashLen)) + 7) / 8
|
|
|
|
binary.BigEndian.PutUint64(ctx.buf[1:], uint64(sigHashLen))
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.buf[8-beLen] = byte(beLen) + 247
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err := ctx.keccak2.Write(ctx.buf[8-beLen : 9]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing len Prefix): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-26 10:18:39 +00:00
|
|
|
if _, err = ctx.keccak2.Write(payload[sigHashPos:sigHashEnd]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash: %w", ParseTransactionErrorPrefix, err)
|
2021-06-26 10:18:39 +00:00
|
|
|
}
|
2021-06-24 23:16:36 +00:00
|
|
|
if legacy {
|
|
|
|
if chainIdLen > 0 {
|
|
|
|
if chainIdBits <= 7 {
|
2021-06-26 10:18:39 +00:00
|
|
|
ctx.buf[0] = byte(ctx.chainId.Uint64())
|
2021-06-24 23:16:36 +00:00
|
|
|
if _, err := ctx.keccak2.Write(ctx.buf[:1]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing legacy chainId): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-06-26 10:18:39 +00:00
|
|
|
binary.BigEndian.PutUint64(ctx.buf[1:9], ctx.chainId[3])
|
|
|
|
binary.BigEndian.PutUint64(ctx.buf[9:17], ctx.chainId[2])
|
|
|
|
binary.BigEndian.PutUint64(ctx.buf[17:25], ctx.chainId[1])
|
|
|
|
binary.BigEndian.PutUint64(ctx.buf[25:33], ctx.chainId[0])
|
2021-06-24 23:16:36 +00:00
|
|
|
ctx.buf[32-chainIdLen] = 128 + byte(chainIdLen)
|
|
|
|
if _, err = ctx.keccak2.Write(ctx.buf[32-chainIdLen : 33]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing legacy chainId): %w", ParseTransactionErrorPrefix, err)
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-26 10:18:39 +00:00
|
|
|
// Encode two zeros
|
|
|
|
ctx.buf[0] = 128
|
|
|
|
ctx.buf[1] = 128
|
|
|
|
if _, err := ctx.keccak2.Write(ctx.buf[:2]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing signHash (hashing zeros after legacy chainId): %w", ParseTransactionErrorPrefix, err)
|
2021-06-26 10:18:39 +00:00
|
|
|
}
|
2021-06-24 23:16:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Squeeze sighash
|
2021-07-30 09:24:20 +00:00
|
|
|
_, _ = ctx.keccak2.(io.Reader).Read(ctx.sighash[:32])
|
|
|
|
//ctx.keccak2.Sum(ctx.sighash[:0])
|
2021-06-24 23:16:36 +00:00
|
|
|
binary.BigEndian.PutUint64(ctx.sig[0:8], ctx.r[3])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[8:16], ctx.r[2])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[16:24], ctx.r[1])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[24:32], ctx.r[0])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[32:40], ctx.s[3])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[40:48], ctx.s[2])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[48:56], ctx.s[1])
|
|
|
|
binary.BigEndian.PutUint64(ctx.sig[56:64], ctx.s[0])
|
|
|
|
ctx.sig[64] = vByte
|
2021-06-26 11:55:32 +00:00
|
|
|
// recover sender
|
|
|
|
if _, err = secp256k1.RecoverPubkeyWithContext(ctx.recCtx, ctx.sighash[:], ctx.sig[:], ctx.buf[:0]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: recovering sender from signature: %w", ParseTransactionErrorPrefix, err)
|
2021-06-26 11:55:32 +00:00
|
|
|
}
|
2021-07-27 05:03:59 +00:00
|
|
|
//apply keccak to the public key
|
2021-06-26 11:55:32 +00:00
|
|
|
ctx.keccak2.Reset()
|
|
|
|
if _, err = ctx.keccak2.Write(ctx.buf[1:65]); err != nil {
|
2021-07-31 08:10:42 +00:00
|
|
|
return nil, sender, 0, fmt.Errorf("%s: computing sender from public key: %w", ParseTransactionErrorPrefix, err)
|
2021-06-26 11:55:32 +00:00
|
|
|
}
|
|
|
|
// squeeze the hash of the public key
|
2021-07-30 09:24:20 +00:00
|
|
|
//ctx.keccak2.Sum(ctx.buf[:0])
|
|
|
|
_, _ = ctx.keccak2.(io.Reader).Read(ctx.buf[:32])
|
2021-07-27 05:03:59 +00:00
|
|
|
//take last 20 bytes as address
|
2021-07-31 08:10:42 +00:00
|
|
|
copy(sender[:], ctx.buf[12:32])
|
|
|
|
return slot, sender, p, nil
|
2021-06-19 22:41:15 +00:00
|
|
|
}
|