commit
a1ef353ae2
@ -57,6 +57,7 @@ type Backend interface {
|
|||||||
|
|
||||||
GetTrie(hash Hash) (Trie, error)
|
GetTrie(hash Hash) (Trie, error)
|
||||||
GetAccountTrie(stateRoot Hash, account Address) (Trie, error)
|
GetAccountTrie(stateRoot Hash, account Address) (Trie, error)
|
||||||
|
GetContractCode(Hash) ([]byte, error)
|
||||||
|
|
||||||
// ChainConfig() *params.ChainConfig
|
// ChainConfig() *params.ChainConfig
|
||||||
// Engine() consensus.Engine
|
// Engine() consensus.Engine
|
||||||
|
@ -49,6 +49,6 @@ A simple implimentation would look like so:
|
|||||||
Access
|
Access
|
||||||
******
|
******
|
||||||
|
|
||||||
As with pre-built plugins, a``.so`` will need to be built from``main.go`` and moved into ``~/.ethereum/plugins``. Geth will need to be started with with a ``http.api=mymamespace`` flag. Additionally you will need to include a ``--http`` flag in order to access the standard json rpc methods.
|
As with pre-built plugins, a``.so`` will need to be built from``main.go`` and moved into ``~/.ethereum/plugins``. Geth will need to be started with with a ``http.api=mynamespace`` flag. Additionally you will need to include a ``--http`` flag in order to access the standard json rpc methods.
|
||||||
|
|
||||||
The plugin can now be accessed with an rpc call to ``mynamespace_helloWorld``.
|
The plugin can now be accessed with an rpc call to ``mynamespace_helloWorld``.
|
||||||
|
@ -14,7 +14,7 @@ Flags
|
|||||||
|
|
||||||
* **Name:** Flags
|
* **Name:** Flags
|
||||||
* **Type:** `flag.FlagSet`_
|
* **Type:** `flag.FlagSet`_
|
||||||
* **Behavior:** This FlagSet will be parsed and your plugin will be able to access the resulting flags. Flags will be passed to Geth from the command line and are intended to of the plugin. Note that if any flags are provided, certain checks are disabled within Geth to avoid failing due to unexpected flags.
|
* **Behavior:** This FlagSet will be parsed and your plugin will be able to access the resulting flags. Flags will be passed to Geth from the command line and are intended to configure the behavior of the plugin. Passed flags must follow ``--`` to be parsed by this FlagSet, which is necessary to avoid Geth failing due to unexpected flags.
|
||||||
|
|
||||||
Subcommands
|
Subcommands
|
||||||
-----------
|
-----------
|
||||||
@ -356,4 +356,4 @@ logging based on the interfaces of `Log15 <https://github.com/inconshreveable/lo
|
|||||||
.. _PluGeth-Utils: https://github.com/openrelayxyz/plugeth-utils
|
.. _PluGeth-Utils: https://github.com/openrelayxyz/plugeth-utils
|
||||||
.. _*cli.Context: https://pkg.go.dev/github.com/urfave/cli#Context
|
.. _*cli.Context: https://pkg.go.dev/github.com/urfave/cli#Context
|
||||||
.. _flag.FlagSet: https://pkg.go.dev/flag#FlagSet
|
.. _flag.FlagSet: https://pkg.go.dev/flag#FlagSet
|
||||||
.. _Native Plugin System: https://pkg.go.dev/plugin
|
.. _Native Plugin System: https://pkg.go.dev/plugin
|
||||||
|
@ -7,7 +7,7 @@ Selected Plugin Hooks
|
|||||||
Plugin Hooks
|
Plugin Hooks
|
||||||
************
|
************
|
||||||
|
|
||||||
Plugeth provides several hooks from which the plugin can capture data from Geth. Additionally in the case of **subcommands** the provided hooks are designed to change the behavior of Geth.
|
Plugeth provides several hooks from which the plugin can capture data from Geth. Additionally in the case of **subcommands** the provided hooks are designed to change the behavior of Geth.
|
||||||
|
|
||||||
Hooks are called from functions within the plugin. For example, if we wanted to bring in data from the StateUpdate hook. We would impliment it like so:
|
Hooks are called from functions within the plugin. For example, if we wanted to bring in data from the StateUpdate hook. We would impliment it like so:
|
||||||
(from `blockupdates`_)
|
(from `blockupdates`_)
|
||||||
@ -26,24 +26,24 @@ Hooks are called from functions within the plugin. For example, if we wanted to
|
|||||||
backend.ChainDb().Put(append([]byte("su"), blockRoot.Bytes()...), data)
|
backend.ChainDb().Put(append([]byte("su"), blockRoot.Bytes()...), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
Many hooks can be deployed in an one plugin as is the case with the **BlockUpdater** plugin.
|
Many hooks can be deployed in one plugin as is the case with the **BlockUpdater** plugin.
|
||||||
|
|
||||||
.. contents:: :local:
|
.. contents:: :local:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
StateUpdate
|
StateUpdate
|
||||||
***********
|
***********
|
||||||
|
|
||||||
**Function Signature**:``func(root common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte)``
|
**Function Signature**:``func(root common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte)``
|
||||||
|
|
||||||
The state update plugin provides a snapshot of the state subsystem in the form of a a stateUpdate object. The stateUpdate object contains all information transformed by a transaction but not the transaction itself.
|
The state update plugin provides a snapshot of the state subsystem in the form of a a stateUpdate object. The stateUpdate object contains all information transformed by a transaction but not the transaction itself.
|
||||||
|
|
||||||
Invoked for each new block, StateUpdate provides the changes to the blockchain state. root corresponds to the state root of the new block. parentRoot corresponds to the state root of the parent block. destructs serves as a set of accounts that self-destructed in this block. accounts maps the hash of each account address to the SlimRLP encoding of the account data. storage maps the hash of each account to a map of that account's stored data.
|
Invoked for each new block, StateUpdate provides the changes to the blockchain state. root corresponds to the state root of the new block. parentRoot corresponds to the state root of the parent block. destructs serves as a set of accounts that self-destructed in this block. accounts maps the hash of each account address to the SlimRLP encoding of the account data. storage maps the hash of each account to a map of that account's stored data.
|
||||||
|
|
||||||
.. warning:: StateUpdate is only called if Geth is running with
|
.. warning:: StateUpdate is only called if Geth is running with
|
||||||
``-snapshots=true``. This is the default behavior for Geth, but if you are explicitly running with ``--snapshot=false`` this function will not be invoked.
|
``-snapshots=true``. This is the default behavior for Geth, but if you are explicitly running with ``--snapshot=false`` this function will not be invoked.
|
||||||
|
|
||||||
|
|
||||||
AppendAncient
|
AppendAncient
|
||||||
*************
|
*************
|
||||||
@ -57,7 +57,7 @@ GetRPCCalls
|
|||||||
|
|
||||||
**Function Signature**:``func(string, string, string)``
|
**Function Signature**:``func(string, string, string)``
|
||||||
|
|
||||||
Invoked when the RPC handler registers a method call. Returns the call ``id``, method ``name``, and any ``params`` that may have been passed in.
|
Invoked when the RPC handler registers a method call. Returns the call ``id``, method ``name``, and any ``params`` that may have been passed in.
|
||||||
|
|
||||||
.. todo:: missing a couple of hooks
|
.. todo:: missing a couple of hooks
|
||||||
|
|
||||||
@ -80,24 +80,24 @@ BlockProcessingError
|
|||||||
|
|
||||||
**Function Signature**:``func(*types.Transaction, *types.Block, error)``
|
**Function Signature**:``func(*types.Transaction, *types.Block, error)``
|
||||||
|
|
||||||
Invoked if an error occurs while processing a transaction. This only applies to errors that would unvalidate the block were this transaction is included not errors such as reverts or opcode errors. Returns a transaction, block, and error.
|
Invoked if an error occurs while processing a transaction. This only applies to errors that would unvalidate the block were this transaction is included not errors such as reverts or opcode errors. Returns a transaction, block, and error.
|
||||||
|
|
||||||
NewHead
|
NewHead
|
||||||
*******
|
*******
|
||||||
|
|
||||||
**Function Signature**:``func(*types.Block, common.Hash, []*types.Log)``
|
**Function Signature**:``func(*types.Block, common.Hash, []*types.Log)``
|
||||||
|
|
||||||
Invoked when a new block becomes the canonical latest block. Returns a block, hash, and log.
|
Invoked when a new block becomes the canonical latest block. Returns a block, hash, and logs.
|
||||||
|
|
||||||
.. note:: If severtal blocks are processed in a group (such as
|
.. note:: If several blocks are processed in a group (such as
|
||||||
during a reorg) this may not be called for each block. You should track the prior latest head if you need to process intermediate blocks.
|
during a reorg) this may not be called for each block. You should track the prior latest head if you need to process intermediate blocks.
|
||||||
|
|
||||||
NewSideBlock
|
NewSideBlock
|
||||||
************
|
************
|
||||||
|
|
||||||
**Function Signature**:``func(*types.Block, common.Hash, []*types.Log)``
|
**Function Signature**:``func(*types.Block, common.Hash, []*types.Log)``
|
||||||
|
|
||||||
Invoked when a block is side-chained. Returns a block, has, and logs.
|
Invoked when a block is side-chained. Returns a block, hash, and logs.
|
||||||
|
|
||||||
.. note:: Blocks passed to this method are non-canonical blocks.
|
.. note:: Blocks passed to this method are non-canonical blocks.
|
||||||
|
|
||||||
@ -107,8 +107,8 @@ Reorg
|
|||||||
|
|
||||||
**Function Signature**:``func(common *types.Block, oldChain, newChain types.Blocks)``
|
**Function Signature**:``func(common *types.Block, oldChain, newChain types.Blocks)``
|
||||||
|
|
||||||
Invoked when a chain reorg occurs, that is; at least one block is removed and one block is added. (``oldChain`` is a list of removed blocks, ``newChain`` is a list of newliy added blocks, and ``common`` is the latest block that is an ancestor to both oldChain and newChain.) Returns a block, a list of old blocks, and a list of new blocks.
|
Invoked when a chain reorg occurs, that is; at least one block is removed and one block is added. (``oldChain`` is a list of removed blocks, ``newChain`` is a list of newliy added blocks, and ``common`` is the latest block that is an ancestor to both oldChain and newChain.) Returns a block, a list of old blocks, and a list of new blocks.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ GetFeed
|
|||||||
=======
|
=======
|
||||||
``GetFeed() Feed``
|
``GetFeed() Feed``
|
||||||
|
|
||||||
Returns a new feed that the plugin can used for publish/subscribe models.
|
Returns a new feed that the plugin can use for publish/subscribe models.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ A GetAPIs method is required in the body of the plugin in order to make the plug
|
|||||||
Subscription Function
|
Subscription Function
|
||||||
*********************
|
*********************
|
||||||
|
|
||||||
For subscriptions (supported on IPC and websockets), a function should take MyService as a reciever and a context.Context object as an argument and return a channel and an error. The following is a subscription function that impliments a timer.
|
For subscriptions (supported on IPC and websockets), a function should take MyService as a reciever and a context.Context object as an argument and return a channel and an error. The following is a subscription function that implements a timer.
|
||||||
|
|
||||||
.. code-block:: Go
|
.. code-block:: Go
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ Access
|
|||||||
.. Note:: Plugins providing subscriptions can be accessed via IPC
|
.. Note:: Plugins providing subscriptions can be accessed via IPC
|
||||||
and websockets. In the below example we will be using `wscat`_ to connect a websocket to a local Geth node.
|
and websockets. In the below example we will be using `wscat`_ to connect a websocket to a local Geth node.
|
||||||
|
|
||||||
As with pre-built plugins, a ``.so`` will need to be built from ``main.go`` and moved into ``~/.ethereum/plugins``. Geth will need to be started with with ``--ws --ws.api=mynamespace``flags. Additionally you will need to include a ``--http`` flag in order to access the standard json rpc methods.
|
As with pre-built plugins, a ``.so`` will need to be built from ``main.go`` and moved into ``~/.ethereum/plugins``. Geth will need to be started with ``--ws --ws.api=mynamespace`` flags. Additionally you will need to include a ``--http`` flag in order to access the standard json rpc methods.
|
||||||
|
|
||||||
After starting Geth, from a seperate terminal run:
|
After starting Geth, from a seperate terminal run:
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ First an empty MyService Struct.
|
|||||||
Map
|
Map
|
||||||
***
|
***
|
||||||
|
|
||||||
Next, a map of tracers to functions returning a ``core.TracerResult`` which will be implimented like so:
|
Next, a map of tracers to functions returning a ``core.TracerResult`` which will be implemented like so:
|
||||||
|
|
||||||
.. code-block:: Go
|
.. code-block:: Go
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ These plugins provide new json rpc methods to access several objects containing
|
|||||||
Subcommand
|
Subcommand
|
||||||
------------
|
------------
|
||||||
|
|
||||||
A subcommand redifines the total behavior of Geth and could stand on its own. In contrast with the other plugin types which, in general, are meant to capture and manipulate information, a subcommand is meant to change the overall behavior of Geth. It may do this in order to capture information but the primary fuctionality is a modulation of geth behaviour.
|
A subcommand redefines the total behavior of Geth and could stand on its own. In contrast with the other plugin types which, in general, are meant to capture and manipulate information, a subcommand is meant to change the overall behavior of Geth. It may do this in order to capture information but the primary fuctionality is a modulation of geth behaviour.
|
||||||
|
|
||||||
Tracers
|
Tracers
|
||||||
-------
|
-------
|
||||||
|
1
go.mod
1
go.mod
@ -16,6 +16,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -17,6 +17,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -1,21 +1,12 @@
|
|||||||
package bls12381
|
package bls12381
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fromHex(s string) []byte {
|
|
||||||
b, err := hex.DecodeString(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *G1) one() *PointG1 {
|
func (g *G1) one() *PointG1 {
|
||||||
one, _ := g.fromBytesUnchecked(
|
one, _ := g.fromBytesUnchecked(
|
||||||
fromHex("" +
|
fromHex("" +
|
||||||
|
@ -17,15 +17,34 @@
|
|||||||
package bls12381
|
package bls12381
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bigFromHex(hex string) *big.Int {
|
// fromHex returns the bytes represented by the hexadecimal string s.
|
||||||
b, _ := hex.DecodeString(strings.TrimPrefix(hex, "0x"))
|
// s may be prefixed with "0x".
|
||||||
return new(big.Int).SetBytes(b)
|
func fromHex(s string) []byte {
|
||||||
|
if has0xPrefix(s) {
|
||||||
|
s = s[2:]
|
||||||
|
}
|
||||||
|
if len(s)%2 == 1 {
|
||||||
|
s = "0" + s
|
||||||
|
}
|
||||||
|
h, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// has0xPrefix validates str begins with '0x' or '0X'.
|
||||||
|
func has0xPrefix(str string) bool {
|
||||||
|
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
|
||||||
|
}
|
||||||
|
|
||||||
|
func bigFromHex(s string) *big.Int {
|
||||||
|
return new(big.Int).SetBytes(fromHex(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeFieldElement expects 64 byte input with zero top 16 bytes,
|
// decodeFieldElement expects 64 byte input with zero top 16 bytes,
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package hasher
|
package hasher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
@ -57,7 +56,7 @@ func returnToPool(st *StackTrie) {
|
|||||||
// in order. Once it determines that a subtree will no longer be inserted
|
// in order. Once it determines that a subtree will no longer be inserted
|
||||||
// into, it will hash it and free up the memory it uses.
|
// into, it will hash it and free up the memory it uses.
|
||||||
type StackTrie struct {
|
type StackTrie struct {
|
||||||
owner core.Hash // the owner of the trie
|
owner core.Hash // the owner of the trie
|
||||||
nodeType uint8 // node type (as in branch, ext, leaf)
|
nodeType uint8 // node type (as in branch, ext, leaf)
|
||||||
val []byte // value contained by this node if it's a leaf
|
val []byte // value contained by this node if it's a leaf
|
||||||
key []byte // key chunk covered by this (leaf|ext) node
|
key []byte // key chunk covered by this (leaf|ext) node
|
||||||
@ -213,9 +212,7 @@ func (st *StackTrie) TryUpdate(key, value []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *StackTrie) Update(key, value []byte) {
|
func (st *StackTrie) Update(key, value []byte) {
|
||||||
if err := st.TryUpdate(key, value); err != nil {
|
st.TryUpdate(key, value)
|
||||||
fmt.Errorf("Unhandled trie error in StackTrie.Update", "err", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StackTrie) Reset() {
|
func (st *StackTrie) Reset() {
|
||||||
|
@ -34,13 +34,43 @@ var (
|
|||||||
CalaverasGenesisHash = core.HexToHash("0xeb9233d066c275efcdfed8037f4fc082770176aefdbcb7691c71da412a5670f2")
|
CalaverasGenesisHash = core.HexToHash("0xeb9233d066c275efcdfed8037f4fc082770176aefdbcb7691c71da412a5670f2")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// TestChainConfig contains every protocol change (EIPs) introduced
|
||||||
|
// and accepted by the Ethereum core developers for testing proposes.
|
||||||
|
TestChainConfig = &ChainConfig{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
DAOForkBlock: nil,
|
||||||
|
DAOForkSupport: false,
|
||||||
|
EIP150Block: big.NewInt(0),
|
||||||
|
EIP155Block: big.NewInt(0),
|
||||||
|
EIP158Block: big.NewInt(0),
|
||||||
|
ByzantiumBlock: big.NewInt(0),
|
||||||
|
ConstantinopleBlock: big.NewInt(0),
|
||||||
|
PetersburgBlock: big.NewInt(0),
|
||||||
|
IstanbulBlock: big.NewInt(0),
|
||||||
|
MuirGlacierBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
ArrowGlacierBlock: big.NewInt(0),
|
||||||
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
|
MergeNetsplitBlock: nil,
|
||||||
|
ShanghaiTime: nil,
|
||||||
|
CancunTime: nil,
|
||||||
|
PragueTime: nil,
|
||||||
|
TerminalTotalDifficulty: nil,
|
||||||
|
TerminalTotalDifficultyPassed: false,
|
||||||
|
Ethash: new(EthashConfig),
|
||||||
|
Clique: nil,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
||||||
// BloomTrie) associated with the appropriate section index and head hash. It is
|
// BloomTrie) associated with the appropriate section index and head hash. It is
|
||||||
// used to start light syncing from this checkpoint and avoid downloading the
|
// used to start light syncing from this checkpoint and avoid downloading the
|
||||||
// entire header chain while still being able to securely access old headers/logs.
|
// entire header chain while still being able to securely access old headers/logs.
|
||||||
type TrustedCheckpoint struct {
|
type TrustedCheckpoint struct {
|
||||||
SectionIndex uint64 `json:"sectionIndex"`
|
SectionIndex uint64 `json:"sectionIndex"`
|
||||||
SectionHead core.Hash `json:"sectionHead"`
|
SectionHead core.Hash `json:"sectionHead"`
|
||||||
CHTRoot core.Hash `json:"chtRoot"`
|
CHTRoot core.Hash `json:"chtRoot"`
|
||||||
BloomRoot core.Hash `json:"bloomRoot"`
|
BloomRoot core.Hash `json:"bloomRoot"`
|
||||||
@ -80,7 +110,7 @@ func (c *TrustedCheckpoint) Empty() bool {
|
|||||||
type CheckpointOracleConfig struct {
|
type CheckpointOracleConfig struct {
|
||||||
Address core.Address `json:"address"`
|
Address core.Address `json:"address"`
|
||||||
Signers []core.Address `json:"signers"`
|
Signers []core.Address `json:"signers"`
|
||||||
Threshold uint64 `json:"threshold"`
|
Threshold uint64 `json:"threshold"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig is the core config which determines the blockchain settings.
|
// ChainConfig is the core config which determines the blockchain settings.
|
||||||
@ -97,7 +127,7 @@ type ChainConfig struct {
|
|||||||
DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork
|
DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork
|
||||||
|
|
||||||
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
|
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
|
||||||
EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
|
EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
|
||||||
EIP150Hash core.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
|
EIP150Hash core.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
|
||||||
|
|
||||||
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
|
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
|
||||||
@ -111,9 +141,9 @@ type ChainConfig struct {
|
|||||||
BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin)
|
BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin)
|
||||||
LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london)
|
LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london)
|
||||||
|
|
||||||
ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
|
ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
|
||||||
GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
|
GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
|
||||||
MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter
|
MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter
|
||||||
|
|
||||||
// Fork scheduling was switched from blocks to timestamps here
|
// Fork scheduling was switched from blocks to timestamps here
|
||||||
|
|
||||||
|
@ -22,6 +22,37 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
|
AllEthashProtocolChanges = &ChainConfig{
|
||||||
|
ChainID: big.NewInt(1337),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
DAOForkBlock: nil,
|
||||||
|
DAOForkSupport: false,
|
||||||
|
EIP150Block: big.NewInt(0),
|
||||||
|
EIP155Block: big.NewInt(0),
|
||||||
|
EIP158Block: big.NewInt(0),
|
||||||
|
ByzantiumBlock: big.NewInt(0),
|
||||||
|
ConstantinopleBlock: big.NewInt(0),
|
||||||
|
PetersburgBlock: big.NewInt(0),
|
||||||
|
IstanbulBlock: big.NewInt(0),
|
||||||
|
MuirGlacierBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
ArrowGlacierBlock: big.NewInt(0),
|
||||||
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
|
MergeNetsplitBlock: nil,
|
||||||
|
ShanghaiTime: nil,
|
||||||
|
CancunTime: nil,
|
||||||
|
PragueTime: nil,
|
||||||
|
TerminalTotalDifficulty: nil,
|
||||||
|
TerminalTotalDifficultyPassed: false,
|
||||||
|
Ethash: new(EthashConfig),
|
||||||
|
Clique: nil,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func TestCheckCompatible(t *testing.T) {
|
func TestCheckCompatible(t *testing.T) {
|
||||||
type test struct {
|
type test struct {
|
||||||
stored, new *ChainConfig
|
stored, new *ChainConfig
|
||||||
|
34
restricted/trie/encoding.go
Normal file
34
restricted/trie/encoding.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package trie
|
||||||
|
|
||||||
|
// HexToCompact converts a hex path to the compact encoded format
|
||||||
|
func HexToCompact(hex []byte) []byte {
|
||||||
|
return hexToCompact(hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexToCompact(hex []byte) []byte {
|
||||||
|
terminator := byte(0)
|
||||||
|
if hasTerm(hex) {
|
||||||
|
terminator = 1
|
||||||
|
hex = hex[:len(hex)-1]
|
||||||
|
}
|
||||||
|
buf := make([]byte, len(hex)/2+1)
|
||||||
|
buf[0] = terminator << 5 // the flag byte
|
||||||
|
if len(hex)&1 == 1 {
|
||||||
|
buf[0] |= 1 << 4 // odd flag
|
||||||
|
buf[0] |= hex[0] // first nibble is contained in the first byte
|
||||||
|
hex = hex[1:]
|
||||||
|
}
|
||||||
|
decodeNibbles(hex, buf[1:])
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeNibbles(nibbles []byte, bytes []byte) {
|
||||||
|
for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
|
||||||
|
bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasTerm returns whether a hex key has the terminator flag.
|
||||||
|
func hasTerm(s []byte) bool {
|
||||||
|
return len(s) > 0 && s[len(s)-1] == 16
|
||||||
|
}
|
169
restricted/trie/iterator.go
Normal file
169
restricted/trie/iterator.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package trie
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/openrelayxyz/plugeth-utils/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeIterator = core.NodeIterator
|
||||||
|
|
||||||
|
// Iterator is a key-value trie iterator that traverses a Trie.
|
||||||
|
type Iterator struct {
|
||||||
|
nodeIt core.NodeIterator
|
||||||
|
|
||||||
|
Key []byte // Current data key on which the iterator is positioned on
|
||||||
|
Value []byte // Current data value on which the iterator is positioned on
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIterator creates a new key-value iterator from a node iterator.
|
||||||
|
// Note that the value returned by the iterator is raw. If the content is encoded
|
||||||
|
// (e.g. storage value is RLP-encoded), it's caller's duty to decode it.
|
||||||
|
func NewIterator(it core.NodeIterator) *Iterator {
|
||||||
|
return &Iterator{
|
||||||
|
nodeIt: it,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next moves the iterator forward one key-value entry.
|
||||||
|
func (it *Iterator) Next() bool {
|
||||||
|
for it.nodeIt.Next(true) {
|
||||||
|
if it.nodeIt.Leaf() {
|
||||||
|
it.Key = it.nodeIt.LeafKey()
|
||||||
|
it.Value = it.nodeIt.LeafBlob()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.Key = nil
|
||||||
|
it.Value = nil
|
||||||
|
it.Err = it.nodeIt.Error()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prove generates the Merkle proof for the leaf node the iterator is currently
|
||||||
|
// positioned on.
|
||||||
|
func (it *Iterator) Prove() [][]byte {
|
||||||
|
return it.nodeIt.LeafProof()
|
||||||
|
}
|
||||||
|
|
||||||
|
type differenceIterator struct {
|
||||||
|
a, b core.NodeIterator // Nodes returned are those in b - a.
|
||||||
|
eof bool // Indicates a has run out of elements
|
||||||
|
count int // Number of nodes scanned on either trie
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDifferenceIterator constructs a NodeIterator that iterates over elements in b that
|
||||||
|
// are not in a. Returns the iterator, and a pointer to an integer recording the number
|
||||||
|
// of nodes seen.
|
||||||
|
func NewDifferenceIterator(a, b core.NodeIterator) (core.NodeIterator, *int) {
|
||||||
|
a.Next(true)
|
||||||
|
it := &differenceIterator{
|
||||||
|
a: a,
|
||||||
|
b: b,
|
||||||
|
}
|
||||||
|
return it, &it.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Hash() core.Hash {
|
||||||
|
return it.b.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Parent() core.Hash {
|
||||||
|
return it.b.Parent()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Leaf() bool {
|
||||||
|
return it.b.Leaf()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) LeafKey() []byte {
|
||||||
|
return it.b.LeafKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) LeafBlob() []byte {
|
||||||
|
return it.b.LeafBlob()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) LeafProof() [][]byte {
|
||||||
|
return it.b.LeafProof()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Path() []byte {
|
||||||
|
return it.b.Path()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) NodeBlob() []byte {
|
||||||
|
return it.b.NodeBlob()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) AddResolver(resolver core.NodeResolver) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Next(bool) bool {
|
||||||
|
// Invariants:
|
||||||
|
// - We always advance at least one element in b.
|
||||||
|
// - At the start of this function, a's path is lexically greater than b's.
|
||||||
|
if !it.b.Next(true) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
it.count++
|
||||||
|
|
||||||
|
if it.eof {
|
||||||
|
// a has reached eof, so we just return all elements from b
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch compareNodes(it.a, it.b) {
|
||||||
|
case -1:
|
||||||
|
// b jumped past a; advance a
|
||||||
|
if !it.a.Next(true) {
|
||||||
|
it.eof = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
it.count++
|
||||||
|
case 1:
|
||||||
|
// b is before a
|
||||||
|
return true
|
||||||
|
case 0:
|
||||||
|
// a and b are identical; skip this whole subtree if the nodes have hashes
|
||||||
|
hasHash := it.a.Hash() == core.Hash{}
|
||||||
|
if !it.b.Next(hasHash) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
it.count++
|
||||||
|
if !it.a.Next(hasHash) {
|
||||||
|
it.eof = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
it.count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) Error() error {
|
||||||
|
if err := it.a.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return it.b.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareNodes(a, b core.NodeIterator) int {
|
||||||
|
if cmp := bytes.Compare(a.Path(), b.Path()); cmp != 0 {
|
||||||
|
return cmp
|
||||||
|
}
|
||||||
|
if a.Leaf() && !b.Leaf() {
|
||||||
|
return -1
|
||||||
|
} else if b.Leaf() && !a.Leaf() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if cmp := bytes.Compare(a.Hash().Bytes(), b.Hash().Bytes()); cmp != 0 {
|
||||||
|
return cmp
|
||||||
|
}
|
||||||
|
if a.Leaf() && b.Leaf() {
|
||||||
|
return bytes.Compare(a.LeafBlob(), b.LeafBlob())
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020 The go-ethereum Authors
|
// Copyright 2021 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/openrelayxyz/plugeth-utils/core"
|
"github.com/openrelayxyz/plugeth-utils/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate gencodec -type AccessTuple -out gen_access_tuple.go
|
//go:generate go run github.com/fjl/gencodec -type AccessTuple -out gen_access_tuple.go
|
||||||
|
|
||||||
// AccessList is an EIP-2930 access list.
|
// AccessList is an EIP-2930 access list.
|
||||||
type AccessList []AccessTuple
|
type AccessList []AccessTuple
|
||||||
@ -44,22 +44,22 @@ func (al AccessList) StorageKeys() int {
|
|||||||
|
|
||||||
// AccessListTx is the data of EIP-2930 access list transactions.
|
// AccessListTx is the data of EIP-2930 access list transactions.
|
||||||
type AccessListTx struct {
|
type AccessListTx struct {
|
||||||
ChainID *big.Int // destination chain ID
|
ChainID *big.Int // destination chain ID
|
||||||
Nonce uint64 // nonce of sender account
|
Nonce uint64 // nonce of sender account
|
||||||
GasPrice *big.Int // wei per gas
|
GasPrice *big.Int // wei per gas
|
||||||
Gas uint64 // gas limit
|
Gas uint64 // gas limit
|
||||||
To *core.Address `rlp:"nil"` // nil means contract creation
|
To *core.Address `rlp:"nil"` // nil means contract creation
|
||||||
Value *big.Int // wei amount
|
Value *big.Int // wei amount
|
||||||
Data []byte // contract invocation input data
|
Data []byte // contract invocation input data
|
||||||
AccessList AccessList // EIP-2930 access list
|
AccessList AccessList // EIP-2930 access list
|
||||||
V, R, S *big.Int // signature values
|
V, R, S *big.Int // signature values
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy creates a deep copy of the transaction data and initializes all fields.
|
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||||
func (tx *AccessListTx) copy() TxData {
|
func (tx *AccessListTx) copy() TxData {
|
||||||
cpy := &AccessListTx{
|
cpy := &AccessListTx{
|
||||||
Nonce: tx.Nonce,
|
Nonce: tx.Nonce,
|
||||||
To: tx.To, // TODO: copy pointed-to address
|
To: copyAddressPtr(tx.To),
|
||||||
Data: core.CopyBytes(tx.Data),
|
Data: core.CopyBytes(tx.Data),
|
||||||
Gas: tx.Gas,
|
Gas: tx.Gas,
|
||||||
// These are copied below.
|
// These are copied below.
|
||||||
@ -96,7 +96,6 @@ func (tx *AccessListTx) copy() TxData {
|
|||||||
// accessors for innerTx.
|
// accessors for innerTx.
|
||||||
func (tx *AccessListTx) txType() byte { return AccessListTxType }
|
func (tx *AccessListTx) txType() byte { return AccessListTxType }
|
||||||
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
|
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
|
||||||
func (tx *AccessListTx) protected() bool { return true }
|
|
||||||
func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
|
func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
|
||||||
func (tx *AccessListTx) data() []byte { return tx.Data }
|
func (tx *AccessListTx) data() []byte { return tx.Data }
|
||||||
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
|
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
|
||||||
@ -105,7 +104,11 @@ func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice }
|
|||||||
func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
||||||
func (tx *AccessListTx) value() *big.Int { return tx.Value }
|
func (tx *AccessListTx) value() *big.Int { return tx.Value }
|
||||||
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
||||||
func (tx *AccessListTx) to() *core.Address { return tx.To }
|
func (tx *AccessListTx) to() *core.Address { return tx.To }
|
||||||
|
|
||||||
|
func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||||
|
return dst.Set(tx.GasPrice)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
|
func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||||
return tx.V, tx.R, tx.S
|
return tx.V, tx.R, tx.S
|
||||||
|
@ -25,8 +25,8 @@ import (
|
|||||||
type DynamicFeeTx struct {
|
type DynamicFeeTx struct {
|
||||||
ChainID *big.Int
|
ChainID *big.Int
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
GasTipCap *big.Int
|
GasTipCap *big.Int // a.k.a. maxPriorityFeePerGas
|
||||||
GasFeeCap *big.Int
|
GasFeeCap *big.Int // a.k.a. maxFeePerGas
|
||||||
Gas uint64
|
Gas uint64
|
||||||
To *core.Address `rlp:"nil"` // nil means contract creation
|
To *core.Address `rlp:"nil"` // nil means contract creation
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
@ -43,7 +43,7 @@ type DynamicFeeTx struct {
|
|||||||
func (tx *DynamicFeeTx) copy() TxData {
|
func (tx *DynamicFeeTx) copy() TxData {
|
||||||
cpy := &DynamicFeeTx{
|
cpy := &DynamicFeeTx{
|
||||||
Nonce: tx.Nonce,
|
Nonce: tx.Nonce,
|
||||||
To: tx.To, // TODO: copy pointed-to address
|
To: copyAddressPtr(tx.To),
|
||||||
Data: core.CopyBytes(tx.Data),
|
Data: core.CopyBytes(tx.Data),
|
||||||
Gas: tx.Gas,
|
Gas: tx.Gas,
|
||||||
// These are copied below.
|
// These are copied below.
|
||||||
@ -84,7 +84,6 @@ func (tx *DynamicFeeTx) copy() TxData {
|
|||||||
// accessors for innerTx.
|
// accessors for innerTx.
|
||||||
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
|
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
|
||||||
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
|
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
|
||||||
func (tx *DynamicFeeTx) protected() bool { return true }
|
|
||||||
func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList }
|
func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList }
|
||||||
func (tx *DynamicFeeTx) data() []byte { return tx.Data }
|
func (tx *DynamicFeeTx) data() []byte { return tx.Data }
|
||||||
func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas }
|
func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas }
|
||||||
@ -93,7 +92,18 @@ func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap }
|
|||||||
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
|
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
|
||||||
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
|
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
|
||||||
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
|
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
|
||||||
func (tx *DynamicFeeTx) to() *core.Address { return tx.To }
|
func (tx *DynamicFeeTx) to() *core.Address { return tx.To }
|
||||||
|
|
||||||
|
func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||||
|
if baseFee == nil {
|
||||||
|
return dst.Set(tx.GasFeeCap)
|
||||||
|
}
|
||||||
|
tip := dst.Sub(tx.GasFeeCap, baseFee)
|
||||||
|
if tip.Cmp(tx.GasTipCap) > 0 {
|
||||||
|
tip.Set(tx.GasTipCap)
|
||||||
|
}
|
||||||
|
return tip.Add(tip, baseFee)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
|
func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||||
return tx.V, tx.R, tx.S
|
return tx.V, tx.R, tx.S
|
||||||
|
@ -22,10 +22,11 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
|||||||
CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
|
CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
TxHash core.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash core.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress core.Address `json:"contractAddress"`
|
ContractAddress core.Address `json:"contractAddress"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
BlockHash core.Hash `json:"blockHash,omitempty"`
|
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"`
|
||||||
|
BlockHash core.Hash `json:"blockHash,omitempty"`
|
||||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||||
TransactionIndex hexutil.Uint `json:"transactionIndex"`
|
TransactionIndex hexutil.Uint `json:"transactionIndex"`
|
||||||
}
|
}
|
||||||
@ -39,6 +40,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
|||||||
enc.TxHash = r.TxHash
|
enc.TxHash = r.TxHash
|
||||||
enc.ContractAddress = r.ContractAddress
|
enc.ContractAddress = r.ContractAddress
|
||||||
enc.GasUsed = hexutil.Uint64(r.GasUsed)
|
enc.GasUsed = hexutil.Uint64(r.GasUsed)
|
||||||
|
enc.EffectiveGasPrice = (*hexutil.Big)(r.EffectiveGasPrice)
|
||||||
enc.BlockHash = r.BlockHash
|
enc.BlockHash = r.BlockHash
|
||||||
enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
|
enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
|
||||||
enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
|
enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
|
||||||
@ -54,10 +56,11 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
|||||||
CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
|
CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
|
||||||
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
TxHash *core.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash *core.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress *core.Address `json:"contractAddress"`
|
ContractAddress *core.Address `json:"contractAddress"`
|
||||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
BlockHash *core.Hash `json:"blockHash,omitempty"`
|
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"`
|
||||||
|
BlockHash *core.Hash `json:"blockHash,omitempty"`
|
||||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||||
TransactionIndex *hexutil.Uint `json:"transactionIndex"`
|
TransactionIndex *hexutil.Uint `json:"transactionIndex"`
|
||||||
}
|
}
|
||||||
@ -97,6 +100,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
|||||||
return errors.New("missing required field 'gasUsed' for Receipt")
|
return errors.New("missing required field 'gasUsed' for Receipt")
|
||||||
}
|
}
|
||||||
r.GasUsed = uint64(*dec.GasUsed)
|
r.GasUsed = uint64(*dec.GasUsed)
|
||||||
|
if dec.EffectiveGasPrice != nil {
|
||||||
|
r.EffectiveGasPrice = (*big.Int)(dec.EffectiveGasPrice)
|
||||||
|
}
|
||||||
if dec.BlockHash != nil {
|
if dec.BlockHash != nil {
|
||||||
r.BlockHash = *dec.BlockHash
|
r.BlockHash = *dec.BlockHash
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/core"
|
"github.com/openrelayxyz/plugeth-utils/core"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/types"
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/crypto"
|
"github.com/openrelayxyz/plugeth-utils/restricted/crypto"
|
||||||
|
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
||||||
|
"github.com/openrelayxyz/plugeth-utils/restricted/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fromHex(data string) []byte {
|
func fromHex(data string) []byte {
|
||||||
@ -136,9 +136,10 @@ func (d *hashToHumanReadable) Reset() {
|
|||||||
d.data = make([]byte, 0)
|
d.data = make([]byte, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *hashToHumanReadable) Update(i []byte, i2 []byte) {
|
func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error {
|
||||||
l := fmt.Sprintf("%x %x\n", i, i2)
|
l := fmt.Sprintf("%x %x\n", i, i2)
|
||||||
d.data = append(d.data, []byte(l)...)
|
d.data = append(d.data, []byte(l)...)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *hashToHumanReadable) Hash() core.Hash {
|
func (d *hashToHumanReadable) Hash() core.Hash {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020 The go-ethereum Authors
|
// Copyright 2021 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
@ -24,13 +24,13 @@ import (
|
|||||||
|
|
||||||
// LegacyTx is the transaction data of regular Ethereum transactions.
|
// LegacyTx is the transaction data of regular Ethereum transactions.
|
||||||
type LegacyTx struct {
|
type LegacyTx struct {
|
||||||
Nonce uint64 // nonce of sender account
|
Nonce uint64 // nonce of sender account
|
||||||
GasPrice *big.Int // wei per gas
|
GasPrice *big.Int // wei per gas
|
||||||
Gas uint64 // gas limit
|
Gas uint64 // gas limit
|
||||||
To *core.Address `rlp:"nil"` // nil means contract creation
|
To *core.Address `rlp:"nil"` // nil means contract creation
|
||||||
Value *big.Int // wei amount
|
Value *big.Int // wei amount
|
||||||
Data []byte // contract invocation input data
|
Data []byte // contract invocation input data
|
||||||
V, R, S *big.Int // signature values
|
V, R, S *big.Int // signature values
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransaction creates an unsigned legacy transaction.
|
// NewTransaction creates an unsigned legacy transaction.
|
||||||
@ -62,7 +62,7 @@ func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPric
|
|||||||
func (tx *LegacyTx) copy() TxData {
|
func (tx *LegacyTx) copy() TxData {
|
||||||
cpy := &LegacyTx{
|
cpy := &LegacyTx{
|
||||||
Nonce: tx.Nonce,
|
Nonce: tx.Nonce,
|
||||||
To: tx.To, // TODO: copy pointed-to address
|
To: copyAddressPtr(tx.To),
|
||||||
Data: core.CopyBytes(tx.Data),
|
Data: core.CopyBytes(tx.Data),
|
||||||
Gas: tx.Gas,
|
Gas: tx.Gas,
|
||||||
// These are initialized below.
|
// These are initialized below.
|
||||||
@ -101,7 +101,11 @@ func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice }
|
|||||||
func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
||||||
func (tx *LegacyTx) value() *big.Int { return tx.Value }
|
func (tx *LegacyTx) value() *big.Int { return tx.Value }
|
||||||
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
||||||
func (tx *LegacyTx) to() *core.Address { return tx.To }
|
func (tx *LegacyTx) to() *core.Address { return tx.To }
|
||||||
|
|
||||||
|
func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||||
|
return dst.Set(tx.GasPrice)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
|
func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||||
return tx.V, tx.R, tx.S
|
return tx.V, tx.R, tx.S
|
||||||
|
@ -25,13 +25,13 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/core"
|
"github.com/openrelayxyz/plugeth-utils/core"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/crypto"
|
"github.com/openrelayxyz/plugeth-utils/restricted/crypto"
|
||||||
|
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/params"
|
"github.com/openrelayxyz/plugeth-utils/restricted/params"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
|
//go:generate go run github.com/fjl/gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
|
||||||
|
|
||||||
var (
|
var (
|
||||||
receiptStatusFailedRLP = []byte{}
|
receiptStatusFailedRLP = []byte{}
|
||||||
@ -60,16 +60,16 @@ type Receipt struct {
|
|||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
|
|
||||||
// Implementation fields: These fields are added by geth when processing a transaction.
|
// Implementation fields: These fields are added by geth when processing a transaction.
|
||||||
// They are stored in the chain database.
|
TxHash core.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
TxHash core.Hash `json:"transactionHash" gencodec:"required"`
|
ContractAddress core.Address `json:"contractAddress"`
|
||||||
ContractAddress core.Address `json:"contractAddress"`
|
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility
|
||||||
|
|
||||||
// Inclusion information: These fields provide information about the inclusion of the
|
// Inclusion information: These fields provide information about the inclusion of the
|
||||||
// transaction corresponding to this receipt.
|
// transaction corresponding to this receipt.
|
||||||
BlockHash core.Hash `json:"blockHash,omitempty"`
|
BlockHash core.Hash `json:"blockHash,omitempty"`
|
||||||
BlockNumber *big.Int `json:"blockNumber,omitempty"`
|
BlockNumber *big.Int `json:"blockNumber,omitempty"`
|
||||||
TransactionIndex uint `json:"transactionIndex"`
|
TransactionIndex uint `json:"transactionIndex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type receiptMarshaling struct {
|
type receiptMarshaling struct {
|
||||||
@ -78,6 +78,7 @@ type receiptMarshaling struct {
|
|||||||
Status hexutil.Uint64
|
Status hexutil.Uint64
|
||||||
CumulativeGasUsed hexutil.Uint64
|
CumulativeGasUsed hexutil.Uint64
|
||||||
GasUsed hexutil.Uint64
|
GasUsed hexutil.Uint64
|
||||||
|
EffectiveGasPrice *hexutil.Big
|
||||||
BlockNumber *hexutil.Big
|
BlockNumber *hexutil.Big
|
||||||
TransactionIndex hexutil.Uint
|
TransactionIndex hexutil.Uint
|
||||||
}
|
}
|
||||||
@ -115,6 +116,9 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
|
|||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
|
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
|
||||||
// into an RLP stream. If no post state is present, byzantium fork is assumed.
|
// into an RLP stream. If no post state is present, byzantium fork is assumed.
|
||||||
|
// For a legacy Receipt this returns RLP([PostStateOrStatus, CumulativeGasUsed, Bloom, Logs])
|
||||||
|
// For a EIP-2718 Receipt this returns RLP(TxType || ReceiptPayload)
|
||||||
|
// For a EIP-2930 Receipt, TxType == 0x01 and ReceiptPayload == RLP([PostStateOrStatus, CumulativeGasUsed, Bloom, Logs])
|
||||||
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
||||||
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
|
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
|
||||||
if r.Type == LegacyTxType {
|
if r.Type == LegacyTxType {
|
||||||
@ -123,13 +127,29 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
|
|||||||
buf := encodeBufferPool.Get().(*bytes.Buffer)
|
buf := encodeBufferPool.Get().(*bytes.Buffer)
|
||||||
defer encodeBufferPool.Put(buf)
|
defer encodeBufferPool.Put(buf)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
buf.WriteByte(r.Type)
|
if err := r.encodeTyped(data, buf); err != nil {
|
||||||
if err := rlp.Encode(buf, data); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, buf.Bytes())
|
return rlp.Encode(w, buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodeTyped writes the canonical encoding of a typed receipt to w.
|
||||||
|
func (r *Receipt) encodeTyped(data *receiptRLP, w *bytes.Buffer) error {
|
||||||
|
w.WriteByte(r.Type)
|
||||||
|
return rlp.Encode(w, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary returns the consensus encoding of the receipt.
|
||||||
|
func (r *Receipt) MarshalBinary() ([]byte, error) {
|
||||||
|
if r.Type == LegacyTxType {
|
||||||
|
return rlp.EncodeToBytes(r)
|
||||||
|
}
|
||||||
|
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := r.encodeTyped(data, &buf)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
|
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
|
||||||
// from an RLP stream.
|
// from an RLP stream.
|
||||||
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
||||||
@ -145,26 +165,49 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
|||||||
}
|
}
|
||||||
r.Type = LegacyTxType
|
r.Type = LegacyTxType
|
||||||
return r.setFromRLP(dec)
|
return r.setFromRLP(dec)
|
||||||
case kind == rlp.String:
|
default:
|
||||||
// It's an EIP-2718 typed tx receipt.
|
// It's an EIP-2718 typed tx receipt.
|
||||||
b, err := s.Bytes()
|
b, err := s.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(b) == 0 {
|
return r.decodeTyped(b)
|
||||||
return errEmptyTypedReceipt
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary decodes the consensus encoding of receipts.
|
||||||
|
// It supports legacy RLP receipts and EIP-2718 typed receipts.
|
||||||
|
func (r *Receipt) UnmarshalBinary(b []byte) error {
|
||||||
|
if len(b) > 0 && b[0] > 0x7f {
|
||||||
|
// It's a legacy receipt decode the RLP
|
||||||
|
var data receiptRLP
|
||||||
|
err := rlp.DecodeBytes(b, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Type = LegacyTxType
|
||||||
|
return r.setFromRLP(data)
|
||||||
|
}
|
||||||
|
// It's an EIP2718 typed transaction envelope.
|
||||||
|
return r.decodeTyped(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeTyped decodes a typed receipt from the canonical format.
|
||||||
|
func (r *Receipt) decodeTyped(b []byte) error {
|
||||||
|
if len(b) <= 1 {
|
||||||
|
return errEmptyTypedReceipt
|
||||||
|
}
|
||||||
|
switch b[0] {
|
||||||
|
case DynamicFeeTxType, AccessListTxType:
|
||||||
|
var data receiptRLP
|
||||||
|
err := rlp.DecodeBytes(b[1:], &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
r.Type = b[0]
|
r.Type = b[0]
|
||||||
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType {
|
return r.setFromRLP(data)
|
||||||
var dec receiptRLP
|
|
||||||
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return r.setFromRLP(dec)
|
|
||||||
}
|
|
||||||
return ErrTxTypeNotSupported
|
|
||||||
default:
|
default:
|
||||||
return rlp.ErrExpectedList
|
return ErrTxTypeNotSupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,8 +251,8 @@ func (r *Receipt) Size() float64 {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
|
// ReceiptForStorage is a wrapper around a Receipt with RLP serialization
|
||||||
// entire content of a receipt, as opposed to only the consensus fields originally.
|
// that omits the Bloom field and deserialization that re-computes it.
|
||||||
type ReceiptForStorage Receipt
|
type ReceiptForStorage Receipt
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder.
|
// EncodeRLP implements rlp.Encoder.
|
||||||
@ -222,7 +265,8 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
|||||||
return rlp.Encode(w, enc)
|
return rlp.Encode(w, enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder.
|
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
||||||
|
// fields of a receipt from an RLP stream.
|
||||||
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
var stored storedReceiptRLP
|
var stored storedReceiptRLP
|
||||||
if err := s.Decode(&stored); err != nil {
|
if err := s.Decode(&stored); err != nil {
|
||||||
@ -234,6 +278,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
|||||||
r.CumulativeGasUsed = stored.CumulativeGasUsed
|
r.CumulativeGasUsed = stored.CumulativeGasUsed
|
||||||
r.Logs = stored.Logs
|
r.Logs = stored.Logs
|
||||||
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
|
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,42 +310,48 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
|||||||
|
|
||||||
// DeriveFields fills the receipts with their computed fields based on consensus
|
// DeriveFields fills the receipts with their computed fields based on consensus
|
||||||
// data and contextual infos like containing block and transactions.
|
// data and contextual infos like containing block and transactions.
|
||||||
func (r Receipts) DeriveFields(config *params.ChainConfig, hash core.Hash, number uint64, txs Transactions) error {
|
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash core.Hash, number uint64, baseFee *big.Int, txs []*Transaction) error {
|
||||||
signer := MakeSigner(config, new(big.Int).SetUint64(number))
|
signer := MakeSigner(config, new(big.Int).SetUint64(number))
|
||||||
|
|
||||||
logIndex := uint(0)
|
logIndex := uint(0)
|
||||||
if len(txs) != len(r) {
|
if len(txs) != len(rs) {
|
||||||
return errors.New("transaction and receipt count mismatch")
|
return errors.New("transaction and receipt count mismatch")
|
||||||
}
|
}
|
||||||
for i := 0; i < len(r); i++ {
|
for i := 0; i < len(rs); i++ {
|
||||||
// The transaction type and hash can be retrieved from the transaction itself
|
// The transaction type and hash can be retrieved from the transaction itself
|
||||||
r[i].Type = txs[i].Type()
|
rs[i].Type = txs[i].Type()
|
||||||
r[i].TxHash = txs[i].Hash()
|
rs[i].TxHash = txs[i].Hash()
|
||||||
|
|
||||||
|
rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee)
|
||||||
|
|
||||||
// block location fields
|
// block location fields
|
||||||
r[i].BlockHash = hash
|
rs[i].BlockHash = hash
|
||||||
r[i].BlockNumber = new(big.Int).SetUint64(number)
|
rs[i].BlockNumber = new(big.Int).SetUint64(number)
|
||||||
r[i].TransactionIndex = uint(i)
|
rs[i].TransactionIndex = uint(i)
|
||||||
|
|
||||||
// The contract address can be derived from the transaction itself
|
// The contract address can be derived from the transaction itself
|
||||||
if txs[i].To() == nil {
|
if txs[i].To() == nil {
|
||||||
// Deriving the signer is expensive, only do if it's actually needed
|
// Deriving the signer is expensive, only do if it's actually needed
|
||||||
from, _ := Sender(signer, txs[i])
|
from, _ := Sender(signer, txs[i])
|
||||||
r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
|
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
|
||||||
|
} else {
|
||||||
|
rs[i].ContractAddress = core.Address{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The used gas can be calculated based on previous r
|
// The used gas can be calculated based on previous r
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
r[i].GasUsed = r[i].CumulativeGasUsed
|
rs[i].GasUsed = rs[i].CumulativeGasUsed
|
||||||
} else {
|
} else {
|
||||||
r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
|
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
// The derived log fields can simply be set from the block and transaction
|
// The derived log fields can simply be set from the block and transaction
|
||||||
for j := 0; j < len(r[i].Logs); j++ {
|
for j := 0; j < len(rs[i].Logs); j++ {
|
||||||
r[i].Logs[j].BlockNumber = number
|
rs[i].Logs[j].BlockNumber = number
|
||||||
r[i].Logs[j].BlockHash = hash
|
rs[i].Logs[j].BlockHash = hash
|
||||||
r[i].Logs[j].TxHash = r[i].TxHash
|
rs[i].Logs[j].TxHash = rs[i].TxHash
|
||||||
r[i].Logs[j].TxIndex = uint(i)
|
rs[i].Logs[j].TxIndex = uint(i)
|
||||||
r[i].Logs[j].Index = logIndex
|
rs[i].Logs[j].Index = logIndex
|
||||||
logIndex++
|
logIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,233 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"encoding/hex"
|
|
||||||
|
"github.com/kylelemons/godebug/diff"
|
||||||
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/core"
|
"github.com/openrelayxyz/plugeth-utils/core"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/crypto"
|
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/params"
|
"github.com/openrelayxyz/plugeth-utils/restricted/params"
|
||||||
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
legacyReceipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
accessListReceipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: AccessListTxType,
|
||||||
|
}
|
||||||
|
eip1559Receipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: DynamicFeeTxType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a few transactions to have receipts for
|
||||||
|
to2 = core.HexToAddress("0x2")
|
||||||
|
to3 = core.HexToAddress("0x3")
|
||||||
|
to4 = core.HexToAddress("0x4")
|
||||||
|
to5 = core.HexToAddress("0x5")
|
||||||
|
to6 = core.HexToAddress("0x6")
|
||||||
|
to7 = core.HexToAddress("0x7")
|
||||||
|
txs = Transactions{
|
||||||
|
NewTx(&LegacyTx{
|
||||||
|
Nonce: 1,
|
||||||
|
Value: big.NewInt(1),
|
||||||
|
Gas: 1,
|
||||||
|
GasPrice: big.NewInt(11),
|
||||||
|
}),
|
||||||
|
NewTx(&LegacyTx{
|
||||||
|
To: &to2,
|
||||||
|
Nonce: 2,
|
||||||
|
Value: big.NewInt(2),
|
||||||
|
Gas: 2,
|
||||||
|
GasPrice: big.NewInt(22),
|
||||||
|
}),
|
||||||
|
NewTx(&AccessListTx{
|
||||||
|
To: &to3,
|
||||||
|
Nonce: 3,
|
||||||
|
Value: big.NewInt(3),
|
||||||
|
Gas: 3,
|
||||||
|
GasPrice: big.NewInt(33),
|
||||||
|
}),
|
||||||
|
// EIP-1559 transactions.
|
||||||
|
NewTx(&DynamicFeeTx{
|
||||||
|
To: &to4,
|
||||||
|
Nonce: 4,
|
||||||
|
Value: big.NewInt(4),
|
||||||
|
Gas: 4,
|
||||||
|
GasTipCap: big.NewInt(44),
|
||||||
|
GasFeeCap: big.NewInt(1045),
|
||||||
|
}),
|
||||||
|
NewTx(&DynamicFeeTx{
|
||||||
|
To: &to5,
|
||||||
|
Nonce: 5,
|
||||||
|
Value: big.NewInt(5),
|
||||||
|
Gas: 5,
|
||||||
|
GasTipCap: big.NewInt(56),
|
||||||
|
GasFeeCap: big.NewInt(1055),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
blockNumber = big.NewInt(1)
|
||||||
|
blockHash = core.BytesToHash([]byte{0x03, 0x14})
|
||||||
|
|
||||||
|
// Create the corresponding receipts
|
||||||
|
receipts = Receipts{
|
||||||
|
&Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
// derived fields:
|
||||||
|
BlockNumber: blockNumber.Uint64(),
|
||||||
|
TxHash: txs[0].Hash(),
|
||||||
|
TxIndex: 0,
|
||||||
|
BlockHash: blockHash,
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
// derived fields:
|
||||||
|
BlockNumber: blockNumber.Uint64(),
|
||||||
|
TxHash: txs[0].Hash(),
|
||||||
|
TxIndex: 0,
|
||||||
|
BlockHash: blockHash,
|
||||||
|
Index: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// derived fields:
|
||||||
|
TxHash: txs[0].Hash(),
|
||||||
|
ContractAddress: core.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
|
||||||
|
GasUsed: 1,
|
||||||
|
EffectiveGasPrice: big.NewInt(11),
|
||||||
|
BlockHash: blockHash,
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
TransactionIndex: 0,
|
||||||
|
},
|
||||||
|
&Receipt{
|
||||||
|
PostState: core.Hash{2}.Bytes(),
|
||||||
|
CumulativeGasUsed: 3,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x22}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
// derived fields:
|
||||||
|
BlockNumber: blockNumber.Uint64(),
|
||||||
|
TxHash: txs[1].Hash(),
|
||||||
|
TxIndex: 1,
|
||||||
|
BlockHash: blockHash,
|
||||||
|
Index: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: core.BytesToAddress([]byte{0x02, 0x22}),
|
||||||
|
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
|
||||||
|
// derived fields:
|
||||||
|
BlockNumber: blockNumber.Uint64(),
|
||||||
|
TxHash: txs[1].Hash(),
|
||||||
|
TxIndex: 1,
|
||||||
|
BlockHash: blockHash,
|
||||||
|
Index: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// derived fields:
|
||||||
|
TxHash: txs[1].Hash(),
|
||||||
|
GasUsed: 2,
|
||||||
|
EffectiveGasPrice: big.NewInt(22),
|
||||||
|
BlockHash: blockHash,
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
TransactionIndex: 1,
|
||||||
|
},
|
||||||
|
&Receipt{
|
||||||
|
Type: AccessListTxType,
|
||||||
|
PostState: core.Hash{3}.Bytes(),
|
||||||
|
CumulativeGasUsed: 6,
|
||||||
|
Logs: []*Log{},
|
||||||
|
// derived fields:
|
||||||
|
TxHash: txs[2].Hash(),
|
||||||
|
GasUsed: 3,
|
||||||
|
EffectiveGasPrice: big.NewInt(33),
|
||||||
|
BlockHash: blockHash,
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
TransactionIndex: 2,
|
||||||
|
},
|
||||||
|
&Receipt{
|
||||||
|
Type: DynamicFeeTxType,
|
||||||
|
PostState: core.Hash{4}.Bytes(),
|
||||||
|
CumulativeGasUsed: 10,
|
||||||
|
Logs: []*Log{},
|
||||||
|
// derived fields:
|
||||||
|
TxHash: txs[3].Hash(),
|
||||||
|
GasUsed: 4,
|
||||||
|
EffectiveGasPrice: big.NewInt(1044),
|
||||||
|
BlockHash: blockHash,
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
TransactionIndex: 3,
|
||||||
|
},
|
||||||
|
&Receipt{
|
||||||
|
Type: DynamicFeeTxType,
|
||||||
|
PostState: core.Hash{5}.Bytes(),
|
||||||
|
CumulativeGasUsed: 15,
|
||||||
|
Logs: []*Log{},
|
||||||
|
// derived fields:
|
||||||
|
TxHash: txs[4].Hash(),
|
||||||
|
GasUsed: 5,
|
||||||
|
EffectiveGasPrice: big.NewInt(1055),
|
||||||
|
BlockHash: blockHash,
|
||||||
|
BlockNumber: blockNumber,
|
||||||
|
TransactionIndex: 4,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func TestDecodeEmptyTypedReceipt(t *testing.T) {
|
func TestDecodeEmptyTypedReceipt(t *testing.T) {
|
||||||
input := []byte{0x80}
|
input := []byte{0x80}
|
||||||
var r Receipt
|
var r Receipt
|
||||||
@ -40,131 +256,62 @@ func TestDecodeEmptyTypedReceipt(t *testing.T) {
|
|||||||
|
|
||||||
// Tests that receipt data can be correctly derived from the contextual infos
|
// Tests that receipt data can be correctly derived from the contextual infos
|
||||||
func TestDeriveFields(t *testing.T) {
|
func TestDeriveFields(t *testing.T) {
|
||||||
// Create a few transactions to have receipts for
|
// Re-derive receipts.
|
||||||
to2 := core.HexToAddress("0x2")
|
basefee := big.NewInt(1000)
|
||||||
to3 := core.HexToAddress("0x3")
|
derivedReceipts := clearComputedFieldsOnReceipts(receipts)
|
||||||
txs := Transactions{
|
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), basefee, txs)
|
||||||
NewTx(&LegacyTx{
|
if err != nil {
|
||||||
Nonce: 1,
|
|
||||||
Value: big.NewInt(1),
|
|
||||||
Gas: 1,
|
|
||||||
GasPrice: big.NewInt(1),
|
|
||||||
}),
|
|
||||||
NewTx(&LegacyTx{
|
|
||||||
To: &to2,
|
|
||||||
Nonce: 2,
|
|
||||||
Value: big.NewInt(2),
|
|
||||||
Gas: 2,
|
|
||||||
GasPrice: big.NewInt(2),
|
|
||||||
}),
|
|
||||||
NewTx(&AccessListTx{
|
|
||||||
To: &to3,
|
|
||||||
Nonce: 3,
|
|
||||||
Value: big.NewInt(3),
|
|
||||||
Gas: 3,
|
|
||||||
GasPrice: big.NewInt(3),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
// Create the corresponding receipts
|
|
||||||
receipts := Receipts{
|
|
||||||
&Receipt{
|
|
||||||
Status: ReceiptStatusFailed,
|
|
||||||
CumulativeGasUsed: 1,
|
|
||||||
Logs: []*Log{
|
|
||||||
{Address: core.BytesToAddress([]byte{0x11})},
|
|
||||||
{Address: core.BytesToAddress([]byte{0x01, 0x11})},
|
|
||||||
},
|
|
||||||
TxHash: txs[0].Hash(),
|
|
||||||
ContractAddress: core.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
|
||||||
GasUsed: 1,
|
|
||||||
},
|
|
||||||
&Receipt{
|
|
||||||
PostState: core.Hash{2}.Bytes(),
|
|
||||||
CumulativeGasUsed: 3,
|
|
||||||
Logs: []*Log{
|
|
||||||
{Address: core.BytesToAddress([]byte{0x22})},
|
|
||||||
{Address: core.BytesToAddress([]byte{0x02, 0x22})},
|
|
||||||
},
|
|
||||||
TxHash: txs[1].Hash(),
|
|
||||||
ContractAddress: core.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
|
||||||
GasUsed: 2,
|
|
||||||
},
|
|
||||||
&Receipt{
|
|
||||||
Type: AccessListTxType,
|
|
||||||
PostState: core.Hash{3}.Bytes(),
|
|
||||||
CumulativeGasUsed: 6,
|
|
||||||
Logs: []*Log{
|
|
||||||
{Address: core.BytesToAddress([]byte{0x33})},
|
|
||||||
{Address: core.BytesToAddress([]byte{0x03, 0x33})},
|
|
||||||
},
|
|
||||||
TxHash: txs[2].Hash(),
|
|
||||||
ContractAddress: core.BytesToAddress([]byte{0x03, 0x33, 0x33}),
|
|
||||||
GasUsed: 3,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Clear all the computed fields and re-derive them
|
|
||||||
number := big.NewInt(1)
|
|
||||||
hash := core.BytesToHash([]byte{0x03, 0x14})
|
|
||||||
|
|
||||||
clearComputedFieldsOnReceipts(t, receipts)
|
|
||||||
if err := receipts.DeriveFields(params.TestChainConfig, hash, number.Uint64(), txs); err != nil {
|
|
||||||
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
||||||
}
|
}
|
||||||
// Iterate over all the computed fields and check that they're correct
|
|
||||||
signer := MakeSigner(params.TestChainConfig, number)
|
|
||||||
|
|
||||||
logIndex := uint(0)
|
// Check diff of receipts against derivedReceipts.
|
||||||
|
r1, err := json.MarshalIndent(receipts, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error marshaling input receipts:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r2, err := json.MarshalIndent(derivedReceipts, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error marshaling derived receipts:", err)
|
||||||
|
}
|
||||||
|
d := diff.Diff(string(r1), string(r2))
|
||||||
|
if d != "" {
|
||||||
|
t.Fatal("receipts differ:", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we can marshal/unmarshal receipts to/from json without errors.
|
||||||
|
// This also confirms that our test receipts contain all the required fields.
|
||||||
|
func TestReceiptJSON(t *testing.T) {
|
||||||
for i := range receipts {
|
for i := range receipts {
|
||||||
if receipts[i].Type != txs[i].Type() {
|
b, err := receipts[i].MarshalJSON()
|
||||||
t.Errorf("receipts[%d].Type = %d, want %d", i, receipts[i].Type, txs[i].Type())
|
if err != nil {
|
||||||
|
t.Fatal("error marshaling receipt to json:", err)
|
||||||
}
|
}
|
||||||
if receipts[i].TxHash != txs[i].Hash() {
|
r := Receipt{}
|
||||||
t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String())
|
err = r.UnmarshalJSON(b)
|
||||||
}
|
if err != nil {
|
||||||
if receipts[i].BlockHash != hash {
|
t.Fatal("error unmarshaling receipt from json:", err)
|
||||||
t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), hash.String())
|
|
||||||
}
|
|
||||||
if receipts[i].BlockNumber.Cmp(number) != 0 {
|
|
||||||
t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), number.String())
|
|
||||||
}
|
|
||||||
if receipts[i].TransactionIndex != uint(i) {
|
|
||||||
t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i)
|
|
||||||
}
|
|
||||||
if receipts[i].GasUsed != txs[i].Gas() {
|
|
||||||
t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].Gas())
|
|
||||||
}
|
|
||||||
if txs[i].To() != nil && receipts[i].ContractAddress != (core.Address{}) {
|
|
||||||
t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (core.Address{}).String())
|
|
||||||
}
|
|
||||||
from, _ := Sender(signer, txs[i])
|
|
||||||
contractAddress := crypto.CreateAddress(from, txs[i].Nonce())
|
|
||||||
if txs[i].To() == nil && receipts[i].ContractAddress != contractAddress {
|
|
||||||
t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), contractAddress.String())
|
|
||||||
}
|
|
||||||
for j := range receipts[i].Logs {
|
|
||||||
if receipts[i].Logs[j].BlockNumber != number.Uint64() {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64())
|
|
||||||
}
|
|
||||||
if receipts[i].Logs[j].BlockHash != hash {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String())
|
|
||||||
}
|
|
||||||
if receipts[i].Logs[j].TxHash != txs[i].Hash() {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
|
|
||||||
}
|
|
||||||
if receipts[i].Logs[j].TxHash != txs[i].Hash() {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
|
|
||||||
}
|
|
||||||
if receipts[i].Logs[j].TxIndex != uint(i) {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i)
|
|
||||||
}
|
|
||||||
if receipts[i].Logs[j].Index != logIndex {
|
|
||||||
t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex)
|
|
||||||
}
|
|
||||||
logIndex++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test we can still parse receipt without EffectiveGasPrice for backwards compatibility, even
|
||||||
|
// though it is required per the spec.
|
||||||
|
func TestEffectiveGasPriceNotRequired(t *testing.T) {
|
||||||
|
r := *receipts[0]
|
||||||
|
r.EffectiveGasPrice = nil
|
||||||
|
b, err := r.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error marshaling receipt to json:", err)
|
||||||
|
}
|
||||||
|
r2 := Receipt{}
|
||||||
|
err = r2.UnmarshalJSON(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error unmarshaling receipt from json:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestTypedReceiptEncodingDecoding reproduces a flaw that existed in the receipt
|
// TestTypedReceiptEncodingDecoding reproduces a flaw that existed in the receipt
|
||||||
// rlp decoder, which failed due to a shadowing error.
|
// rlp decoder, which failed due to a shadowing error.
|
||||||
func TestTypedReceiptEncodingDecoding(t *testing.T) {
|
func TestTypedReceiptEncodingDecoding(t *testing.T) {
|
||||||
@ -193,41 +340,135 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) {
|
func TestReceiptMarshalBinary(t *testing.T) {
|
||||||
t.Helper()
|
// Legacy Receipt
|
||||||
|
legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt})
|
||||||
|
have, err := legacyReceipt.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal binary error: %v", err)
|
||||||
|
}
|
||||||
|
legacyReceipts := Receipts{legacyReceipt}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
legacyReceipts.EncodeIndex(0, buf)
|
||||||
|
haveEncodeIndex := buf.Bytes()
|
||||||
|
if !bytes.Equal(have, haveEncodeIndex) {
|
||||||
|
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
|
||||||
|
}
|
||||||
|
buf.Reset()
|
||||||
|
if err := legacyReceipt.EncodeRLP(buf); err != nil {
|
||||||
|
t.Fatalf("encode rlp error: %v", err)
|
||||||
|
}
|
||||||
|
haveRLPEncode := buf.Bytes()
|
||||||
|
if !bytes.Equal(have, haveRLPEncode) {
|
||||||
|
t.Errorf("BinaryMarshal and EncodeRLP mismatch for legacy tx, got %x want %x", have, haveRLPEncode)
|
||||||
|
}
|
||||||
|
legacyWant, _ := hex.DecodeString("f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
|
if !bytes.Equal(have, legacyWant) {
|
||||||
|
t.Errorf("encoded RLP mismatch, got %x want %x", have, legacyWant)
|
||||||
|
}
|
||||||
|
|
||||||
for _, receipt := range receipts {
|
// 2930 Receipt
|
||||||
clearComputedFieldsOnReceipt(t, receipt)
|
buf.Reset()
|
||||||
|
accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt})
|
||||||
|
have, err = accessListReceipt.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal binary error: %v", err)
|
||||||
|
}
|
||||||
|
accessListReceipts := Receipts{accessListReceipt}
|
||||||
|
accessListReceipts.EncodeIndex(0, buf)
|
||||||
|
haveEncodeIndex = buf.Bytes()
|
||||||
|
if !bytes.Equal(have, haveEncodeIndex) {
|
||||||
|
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
|
||||||
|
}
|
||||||
|
accessListWant, _ := hex.DecodeString("01f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
|
if !bytes.Equal(have, accessListWant) {
|
||||||
|
t.Errorf("encoded RLP mismatch, got %x want %x", have, accessListWant)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1559 Receipt
|
||||||
|
buf.Reset()
|
||||||
|
eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt})
|
||||||
|
have, err = eip1559Receipt.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal binary error: %v", err)
|
||||||
|
}
|
||||||
|
eip1559Receipts := Receipts{eip1559Receipt}
|
||||||
|
eip1559Receipts.EncodeIndex(0, buf)
|
||||||
|
haveEncodeIndex = buf.Bytes()
|
||||||
|
if !bytes.Equal(have, haveEncodeIndex) {
|
||||||
|
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
|
||||||
|
}
|
||||||
|
eip1559Want, _ := hex.DecodeString("02f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
|
if !bytes.Equal(have, eip1559Want) {
|
||||||
|
t.Errorf("encoded RLP mismatch, got %x want %x", have, eip1559Want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearComputedFieldsOnReceipt(t *testing.T, receipt *Receipt) {
|
func TestReceiptUnmarshalBinary(t *testing.T) {
|
||||||
t.Helper()
|
// Legacy Receipt
|
||||||
|
legacyBinary, _ := hex.DecodeString("f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
|
gotLegacyReceipt := new(Receipt)
|
||||||
|
if err := gotLegacyReceipt.UnmarshalBinary(legacyBinary); err != nil {
|
||||||
|
t.Fatalf("unmarshal binary error: %v", err)
|
||||||
|
}
|
||||||
|
legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt})
|
||||||
|
if !reflect.DeepEqual(gotLegacyReceipt, legacyReceipt) {
|
||||||
|
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotLegacyReceipt, legacyReceipt)
|
||||||
|
}
|
||||||
|
|
||||||
receipt.TxHash = core.Hash{}
|
// 2930 Receipt
|
||||||
receipt.BlockHash = core.Hash{}
|
accessListBinary, _ := hex.DecodeString("01f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
receipt.BlockNumber = big.NewInt(math.MaxUint32)
|
gotAccessListReceipt := new(Receipt)
|
||||||
receipt.TransactionIndex = math.MaxUint32
|
if err := gotAccessListReceipt.UnmarshalBinary(accessListBinary); err != nil {
|
||||||
receipt.ContractAddress = core.Address{}
|
t.Fatalf("unmarshal binary error: %v", err)
|
||||||
receipt.GasUsed = 0
|
}
|
||||||
|
accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt})
|
||||||
|
if !reflect.DeepEqual(gotAccessListReceipt, accessListReceipt) {
|
||||||
|
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotAccessListReceipt, accessListReceipt)
|
||||||
|
}
|
||||||
|
|
||||||
clearComputedFieldsOnLogs(t, receipt.Logs)
|
// 1559 Receipt
|
||||||
}
|
eip1559RctBinary, _ := hex.DecodeString("02f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
|
||||||
|
got1559Receipt := new(Receipt)
|
||||||
func clearComputedFieldsOnLogs(t *testing.T, logs []*Log) {
|
if err := got1559Receipt.UnmarshalBinary(eip1559RctBinary); err != nil {
|
||||||
t.Helper()
|
t.Fatalf("unmarshal binary error: %v", err)
|
||||||
|
}
|
||||||
for _, log := range logs {
|
eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt})
|
||||||
clearComputedFieldsOnLog(t, log)
|
if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) {
|
||||||
|
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearComputedFieldsOnLog(t *testing.T, log *Log) {
|
func clearComputedFieldsOnReceipts(receipts []*Receipt) []*Receipt {
|
||||||
t.Helper()
|
r := make([]*Receipt, len(receipts))
|
||||||
|
for i, receipt := range receipts {
|
||||||
log.BlockNumber = math.MaxUint32
|
r[i] = clearComputedFieldsOnReceipt(receipt)
|
||||||
log.BlockHash = core.Hash{}
|
}
|
||||||
log.TxHash = core.Hash{}
|
return r
|
||||||
log.TxIndex = math.MaxUint32
|
}
|
||||||
log.Index = math.MaxUint32
|
|
||||||
|
func clearComputedFieldsOnReceipt(receipt *Receipt) *Receipt {
|
||||||
|
cpy := *receipt
|
||||||
|
cpy.TxHash = core.Hash{0xff, 0xff, 0x11}
|
||||||
|
cpy.BlockHash = core.Hash{0xff, 0xff, 0x22}
|
||||||
|
cpy.BlockNumber = big.NewInt(math.MaxUint32)
|
||||||
|
cpy.TransactionIndex = math.MaxUint32
|
||||||
|
cpy.ContractAddress = core.Address{0xff, 0xff, 0x33}
|
||||||
|
cpy.GasUsed = 0xffffffff
|
||||||
|
cpy.Logs = clearComputedFieldsOnLogs(receipt.Logs)
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearComputedFieldsOnLogs(logs []*Log) []*Log {
|
||||||
|
l := make([]*Log, len(logs))
|
||||||
|
for i, log := range logs {
|
||||||
|
cpy := *log
|
||||||
|
cpy.BlockNumber = math.MaxUint32
|
||||||
|
cpy.BlockHash = core.Hash{}
|
||||||
|
cpy.TxHash = core.Hash{}
|
||||||
|
cpy.TxIndex = math.MaxUint32
|
||||||
|
cpy.Index = math.MaxUint32
|
||||||
|
l[i] = &cpy
|
||||||
|
}
|
||||||
|
return l
|
||||||
}
|
}
|
||||||
|
@ -89,9 +89,20 @@ type TxData interface {
|
|||||||
|
|
||||||
rawSignatureValues() (v, r, s *big.Int)
|
rawSignatureValues() (v, r, s *big.Int)
|
||||||
setSignatureValues(chainID, v, r, s *big.Int)
|
setSignatureValues(chainID, v, r, s *big.Int)
|
||||||
|
|
||||||
|
// effectiveGasPrice computes the gas price paid by the transaction, given
|
||||||
|
// the inclusion block baseFee.
|
||||||
|
//
|
||||||
|
// Unlike other TxData methods, the returned *big.Int should be an independent
|
||||||
|
// copy of the computed value, i.e. callers are allowed to mutate the result.
|
||||||
|
// Method implementations can use 'dst' to store the result.
|
||||||
|
effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder
|
// EncodeRLP implements rlp.Encoder
|
||||||
|
// For a legacy Transaction this returns RLP([AccountNonce, GasPrice, GasLimit, Recipient, Amount, Data, V, R, S])
|
||||||
|
// For a EIP-2718 Transaction this returns RLP(TxType || TxPayload)
|
||||||
|
// For a EIP-2930 Transaction, TxType == 0x01 and TxPayload == RLP([ChainID, AccountNonce, GasPrice, GasLimit, Recipient, Amount, Data, AccessList, V, R, S]
|
||||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
||||||
if tx.Type() == LegacyTxType {
|
if tx.Type() == LegacyTxType {
|
||||||
return rlp.Encode(w, tx.inner)
|
return rlp.Encode(w, tx.inner)
|
||||||
@ -112,9 +123,10 @@ func (tx *Transaction) encodeTyped(w *bytes.Buffer) error {
|
|||||||
return rlp.Encode(w, tx.inner)
|
return rlp.Encode(w, tx.inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary returns the canonical encoding of the transaction.
|
// MarshalBinary returns the canonical consensus encoding of the transaction.
|
||||||
// For legacy transactions, it returns the RLP encoding. For EIP-2718 typed
|
// For a legacy Transaction this returns RLP([AccountNonce, GasPrice, GasLimit, Recipient, Amount, Data, V, R, S])
|
||||||
// transactions, it returns the type and payload.
|
// For a EIP-2718 Transaction this returns TxType || TxPayload
|
||||||
|
// For a EIP-2930 Transaction, TxType == 0x01 and TxPayload == RLP([ChainID, AccountNonce, GasPrice, GasLimit, Recipient, Amount, Data, AccessList, V, R, S]
|
||||||
func (tx *Transaction) MarshalBinary() ([]byte, error) {
|
func (tx *Transaction) MarshalBinary() ([]byte, error) {
|
||||||
if tx.Type() == LegacyTxType {
|
if tx.Type() == LegacyTxType {
|
||||||
return rlp.EncodeToBytes(tx.inner)
|
return rlp.EncodeToBytes(tx.inner)
|
||||||
@ -135,10 +147,10 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
|||||||
var inner LegacyTx
|
var inner LegacyTx
|
||||||
err := s.Decode(&inner)
|
err := s.Decode(&inner)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tx.setDecoded(&inner, int(rlp.ListSize(size)))
|
tx.setDecoded(&inner, rlp.ListSize(size))
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
case kind == rlp.String:
|
default:
|
||||||
// It's an EIP-2718 typed TX envelope.
|
// It's an EIP-2718 typed TX envelope.
|
||||||
var b []byte
|
var b []byte
|
||||||
if b, err = s.Bytes(); err != nil {
|
if b, err = s.Bytes(); err != nil {
|
||||||
@ -146,11 +158,9 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
|||||||
}
|
}
|
||||||
inner, err := tx.decodeTyped(b)
|
inner, err := tx.decodeTyped(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tx.setDecoded(inner, len(b))
|
tx.setDecoded(inner, uint64(len(b)))
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
default:
|
|
||||||
return rlp.ErrExpectedList
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +174,7 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.setDecoded(&data, len(b))
|
tx.setDecoded(&data, uint64(len(b)))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// It's an EIP2718 typed transaction envelope.
|
// It's an EIP2718 typed transaction envelope.
|
||||||
@ -172,13 +182,13 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.setDecoded(inner, len(b))
|
tx.setDecoded(inner, uint64(len(b)))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeTyped decodes a typed transaction from the canonical format.
|
// decodeTyped decodes a typed transaction from the canonical format.
|
||||||
func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
||||||
if len(b) == 0 {
|
if len(b) <= 1 {
|
||||||
return nil, errEmptyTypedTx
|
return nil, errEmptyTypedTx
|
||||||
}
|
}
|
||||||
switch b[0] {
|
switch b[0] {
|
||||||
@ -196,11 +206,11 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setDecoded sets the inner transaction and size after decoding.
|
// setDecoded sets the inner transaction and size after decoding.
|
||||||
func (tx *Transaction) setDecoded(inner TxData, size int) {
|
func (tx *Transaction) setDecoded(inner TxData, size uint64) {
|
||||||
tx.inner = inner
|
tx.inner = inner
|
||||||
tx.time = time.Now()
|
tx.time = time.Now()
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
tx.size.Store(float64(size))
|
tx.size.Store(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,13 +298,7 @@ func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() }
|
|||||||
// To returns the recipient address of the transaction.
|
// To returns the recipient address of the transaction.
|
||||||
// For contract-creation transactions, To returns nil.
|
// For contract-creation transactions, To returns nil.
|
||||||
func (tx *Transaction) To() *core.Address {
|
func (tx *Transaction) To() *core.Address {
|
||||||
// Copy the pointed-to address.
|
return copyAddressPtr(tx.inner.to())
|
||||||
ito := tx.inner.to()
|
|
||||||
if ito == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cpy := *ito
|
|
||||||
return &cpy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cost returns gas * gasPrice + value.
|
// Cost returns gas * gasPrice + value.
|
||||||
@ -384,16 +388,21 @@ func (tx *Transaction) Hash() core.Hash {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the true RLP encoded storage size of the transaction, either by
|
// Size returns the true encoded storage size of the transaction, either by encoding
|
||||||
// encoding and returning it, or returning a previously cached value.
|
// and returning it, or returning a previously cached value.
|
||||||
func (tx *Transaction) Size() float64 {
|
func (tx *Transaction) Size() uint64 {
|
||||||
if size := tx.size.Load(); size != nil {
|
if size := tx.size.Load(); size != nil {
|
||||||
return size.(float64)
|
return size.(uint64)
|
||||||
}
|
}
|
||||||
c := writeCounter(0)
|
c := writeCounter(0)
|
||||||
rlp.Encode(&c, &tx.inner)
|
rlp.Encode(&c, &tx.inner)
|
||||||
tx.size.Store(float64(c))
|
|
||||||
return float64(c)
|
size := uint64(c)
|
||||||
|
if tx.Type() != LegacyTxType {
|
||||||
|
size += 1 // type byte
|
||||||
|
}
|
||||||
|
tx.size.Store(size)
|
||||||
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given signature.
|
// WithSignature returns a new transaction with the given signature.
|
||||||
@ -444,6 +453,24 @@ func TxDifference(a, b Transactions) Transactions {
|
|||||||
return keep
|
return keep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashDifference returns a new set which is the difference between a and b.
|
||||||
|
func HashDifference(a, b []core.Hash) []core.Hash {
|
||||||
|
keep := make([]core.Hash, 0, len(a))
|
||||||
|
|
||||||
|
remove := make(map[core.Hash]struct{})
|
||||||
|
for _, hash := range b {
|
||||||
|
remove[hash] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hash := range a {
|
||||||
|
if _, ok := remove[hash]; !ok {
|
||||||
|
keep = append(keep, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keep
|
||||||
|
}
|
||||||
|
|
||||||
// TxByNonce implements the sort interface to allow sorting a list of transactions
|
// TxByNonce implements the sort interface to allow sorting a list of transactions
|
||||||
// by their nonces. This is usually only useful for sorting transactions from a
|
// by their nonces. This is usually only useful for sorting transactions from a
|
||||||
// single account, otherwise a nonce comparison doesn't make much sense.
|
// single account, otherwise a nonce comparison doesn't make much sense.
|
||||||
@ -497,6 +524,7 @@ func (s *TxByPriceAndTime) Pop() interface{} {
|
|||||||
old := *s
|
old := *s
|
||||||
n := len(old)
|
n := len(old)
|
||||||
x := old[n-1]
|
x := old[n-1]
|
||||||
|
old[n-1] = nil
|
||||||
*s = old[0 : n-1]
|
*s = old[0 : n-1]
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -506,9 +534,9 @@ func (s *TxByPriceAndTime) Pop() interface{} {
|
|||||||
// entire batches of transactions for non-executable accounts.
|
// entire batches of transactions for non-executable accounts.
|
||||||
type TransactionsByPriceAndNonce struct {
|
type TransactionsByPriceAndNonce struct {
|
||||||
txs map[core.Address]Transactions // Per account nonce-sorted list of transactions
|
txs map[core.Address]Transactions // Per account nonce-sorted list of transactions
|
||||||
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
||||||
signer Signer // Signer for the set of transactions
|
signer Signer // Signer for the set of transactions
|
||||||
baseFee *big.Int // Current base fee
|
baseFee *big.Int // Current base fee
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
||||||
@ -569,70 +597,11 @@ func (t *TransactionsByPriceAndNonce) Pop() {
|
|||||||
heap.Pop(&t.heads)
|
heap.Pop(&t.heads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is a fully derived transaction and implements core.Message
|
// copyAddressPtr copies an address.
|
||||||
//
|
func copyAddressPtr(a *core.Address) *core.Address {
|
||||||
// NOTE: In a future PR this will be removed.
|
if a == nil {
|
||||||
type Message struct {
|
return nil
|
||||||
to *core.Address
|
|
||||||
from core.Address
|
|
||||||
nonce uint64
|
|
||||||
amount *big.Int
|
|
||||||
gasLimit uint64
|
|
||||||
gasPrice *big.Int
|
|
||||||
gasFeeCap *big.Int
|
|
||||||
gasTipCap *big.Int
|
|
||||||
data []byte
|
|
||||||
accessList AccessList
|
|
||||||
checkNonce bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessage(from core.Address, to *core.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, checkNonce bool) Message {
|
|
||||||
return Message{
|
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
nonce: nonce,
|
|
||||||
amount: amount,
|
|
||||||
gasLimit: gasLimit,
|
|
||||||
gasPrice: gasPrice,
|
|
||||||
gasFeeCap: gasFeeCap,
|
|
||||||
gasTipCap: gasTipCap,
|
|
||||||
data: data,
|
|
||||||
accessList: accessList,
|
|
||||||
checkNonce: checkNonce,
|
|
||||||
}
|
}
|
||||||
|
cpy := *a
|
||||||
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsMessage returns the transaction as a core.Message.
|
|
||||||
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
|
|
||||||
msg := Message{
|
|
||||||
nonce: tx.Nonce(),
|
|
||||||
gasLimit: tx.Gas(),
|
|
||||||
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
|
||||||
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
|
||||||
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
|
||||||
to: tx.To(),
|
|
||||||
amount: tx.Value(),
|
|
||||||
data: tx.Data(),
|
|
||||||
accessList: tx.AccessList(),
|
|
||||||
checkNonce: true,
|
|
||||||
}
|
|
||||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
|
||||||
if baseFee != nil {
|
|
||||||
msg.gasPrice = bigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
msg.from, err = Sender(s, tx)
|
|
||||||
return msg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Message) From() core.Address { return m.from }
|
|
||||||
func (m Message) To() *core.Address { return m.to }
|
|
||||||
func (m Message) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap }
|
|
||||||
func (m Message) GasTipCap() *big.Int { return m.gasTipCap }
|
|
||||||
func (m Message) Value() *big.Int { return m.amount }
|
|
||||||
func (m Message) Gas() uint64 { return m.gasLimit }
|
|
||||||
func (m Message) Nonce() uint64 { return m.nonce }
|
|
||||||
func (m Message) Data() []byte { return m.data }
|
|
||||||
func (m Message) AccessList() AccessList { return m.accessList }
|
|
||||||
func (m Message) CheckNonce() bool { return m.checkNonce }
|
|
||||||
|
Loading…
Reference in New Issue
Block a user