Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
46769845
Unverified
Commit
46769845
authored
Jan 04, 2023
by
Matthew Slipper
Committed by
GitHub
Jan 04, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4590 from ethereum-optimism/develop
Trigger release
parents
0df27c84
74f0a378
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
474 additions
and
18 deletions
+474
-18
great-cherries-bake.md
.changeset/great-cherries-bake.md
+1
-1
weak-crabs-reflect.md
.changeset/weak-crabs-reflect.md
+1
-1
release.yml
.github/workflows/release.yml
+1
-0
receipts.go
op-node/sources/receipts.go
+25
-15
receipts_test.go
op-node/sources/receipts_test.go
+305
-0
random.go
op-node/testutils/random.go
+140
-0
package.json
packages/balance-monitor/package.json
+1
-1
No files found.
.changeset/great-cherries-bake.md
View file @
46769845
---
---
'
minimum-balance-agent
'
:
patch
'
@eth-optimism/balance-monitor
'
:
patch
---
---
Added basic balance monitoring
Added basic balance monitoring
.changeset/weak-crabs-reflect.md
View file @
46769845
---
---
'
minimum-balance-agent
'
:
patch
'
@eth-optimism/balance-monitor
'
:
patch
---
---
Created the Balance Monitoring package
Created the Balance Monitoring package
.github/workflows/release.yml
View file @
46769845
...
@@ -18,6 +18,7 @@ jobs:
...
@@ -18,6 +18,7 @@ jobs:
data-transport-layer
:
${{ steps.packages.outputs.data-transport-layer }}
data-transport-layer
:
${{ steps.packages.outputs.data-transport-layer }}
contracts
:
${{ steps.packages.outputs.contracts }}
contracts
:
${{ steps.packages.outputs.contracts }}
contracts-bedrock
:
${{ steps.packages.outputs.contracts-bedrock }}
contracts-bedrock
:
${{ steps.packages.outputs.contracts-bedrock }}
balance-monitor
:
${{ steps.packages.outputs.balance-monitor }}
gas-oracle
:
${{ steps.packages.outputs.gas-oracle }}
gas-oracle
:
${{ steps.packages.outputs.gas-oracle }}
replica-healthcheck
:
${{ steps.packages.outputs.replica-healthcheck }}
replica-healthcheck
:
${{ steps.packages.outputs.replica-healthcheck }}
proxyd
:
${{ steps.packages.outputs.proxyd }}
proxyd
:
${{ steps.packages.outputs.proxyd }}
...
...
op-node/sources/receipts.go
View file @
46769845
...
@@ -16,6 +16,9 @@ import (
...
@@ -16,6 +16,9 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/eth"
)
)
// validateReceipts validates that the receipt contents are valid.
// Warning: contractAddress is not verified, since it is a more expensive operation for data we do not use.
// See go-ethereum/crypto.CreateAddress to verify contract deployment address data based on sender and tx nonce.
func
validateReceipts
(
block
eth
.
BlockID
,
receiptHash
common
.
Hash
,
txHashes
[]
common
.
Hash
,
receipts
[]
*
types
.
Receipt
)
error
{
func
validateReceipts
(
block
eth
.
BlockID
,
receiptHash
common
.
Hash
,
txHashes
[]
common
.
Hash
,
receipts
[]
*
types
.
Receipt
)
error
{
if
len
(
receipts
)
!=
len
(
txHashes
)
{
if
len
(
receipts
)
!=
len
(
txHashes
)
{
return
fmt
.
Errorf
(
"got %d receipts but expected %d"
,
len
(
receipts
),
len
(
txHashes
))
return
fmt
.
Errorf
(
"got %d receipts but expected %d"
,
len
(
receipts
),
len
(
txHashes
))
...
@@ -28,6 +31,7 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
...
@@ -28,6 +31,7 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
// We don't trust the RPC to provide consistent cached receipt info that we use for critical rollup derivation work.
// We don't trust the RPC to provide consistent cached receipt info that we use for critical rollup derivation work.
// Let's check everything quickly.
// Let's check everything quickly.
logIndex
:=
uint
(
0
)
logIndex
:=
uint
(
0
)
cumulativeGas
:=
uint64
(
0
)
for
i
,
r
:=
range
receipts
{
for
i
,
r
:=
range
receipts
{
if
r
==
nil
{
// on reorgs or other cases the receipts may disappear before they can be retrieved.
if
r
==
nil
{
// on reorgs or other cases the receipts may disappear before they can be retrieved.
return
fmt
.
Errorf
(
"receipt of tx %d returns nil on retrieval"
,
i
)
return
fmt
.
Errorf
(
"receipt of tx %d returns nil on retrieval"
,
i
)
...
@@ -44,6 +48,9 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
...
@@ -44,6 +48,9 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
if
r
.
BlockHash
!=
block
.
Hash
{
if
r
.
BlockHash
!=
block
.
Hash
{
return
fmt
.
Errorf
(
"receipt %d has unexpected block hash %s, expected %s"
,
i
,
r
.
BlockHash
,
block
.
Hash
)
return
fmt
.
Errorf
(
"receipt %d has unexpected block hash %s, expected %s"
,
i
,
r
.
BlockHash
,
block
.
Hash
)
}
}
if
expected
:=
r
.
CumulativeGasUsed
-
cumulativeGas
;
r
.
GasUsed
!=
expected
{
return
fmt
.
Errorf
(
"receipt %d has invalid gas used metadata: %d, expected %d"
,
i
,
r
.
GasUsed
,
expected
)
}
for
j
,
log
:=
range
r
.
Logs
{
for
j
,
log
:=
range
r
.
Logs
{
if
log
.
Index
!=
logIndex
{
if
log
.
Index
!=
logIndex
{
return
fmt
.
Errorf
(
"log %d (%d of tx %d) has unexpected log index %d"
,
logIndex
,
j
,
i
,
log
.
Index
)
return
fmt
.
Errorf
(
"log %d (%d of tx %d) has unexpected log index %d"
,
logIndex
,
j
,
i
,
log
.
Index
)
...
@@ -65,10 +72,10 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
...
@@ -65,10 +72,10 @@ func validateReceipts(block eth.BlockID, receiptHash common.Hash, txHashes []com
}
}
logIndex
++
logIndex
++
}
}
cumulativeGas
=
r
.
CumulativeGasUsed
// Note: 3 non-consensus L1 receipt fields are ignored:
// Note: 3 non-consensus L1 receipt fields are ignored:
// PostState - not part of L1 ethereum anymore since EIP 658 (part of Byzantium)
// PostState - not part of L1 ethereum anymore since EIP 658 (part of Byzantium)
// ContractAddress - we do not care about contract deployments
// ContractAddress - we do not care about contract deployments
// GasUsed - we do not care about L1 gas usage of txs
// And Optimism L1 fee meta-data in the receipt is ignored as well
// And Optimism L1 fee meta-data in the receipt is ignored as well
}
}
...
@@ -250,7 +257,7 @@ const (
...
@@ -250,7 +257,7 @@ const (
func
AvailableReceiptsFetchingMethods
(
kind
RPCProviderKind
)
ReceiptsFetchingMethod
{
func
AvailableReceiptsFetchingMethods
(
kind
RPCProviderKind
)
ReceiptsFetchingMethod
{
switch
kind
{
switch
kind
{
case
RPCKindAlchemy
:
case
RPCKindAlchemy
:
return
AlchemyGetTransactionReceipts
|
EthGetTransactionReceiptBatch
return
AlchemyGetTransactionReceipts
|
EthGet
BlockReceipts
|
EthGet
TransactionReceiptBatch
case
RPCKindQuickNode
:
case
RPCKindQuickNode
:
return
DebugGetRawReceipts
|
EthGetBlockReceipts
|
EthGetTransactionReceiptBatch
return
DebugGetRawReceipts
|
EthGetBlockReceipts
|
EthGetTransactionReceiptBatch
case
RPCKindInfura
:
case
RPCKindInfura
:
...
@@ -287,9 +294,6 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc
...
@@ -287,9 +294,6 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc
if
available
&
EthGetBlockReceipts
!=
0
&&
txCount
>
500
/
15
{
if
available
&
EthGetBlockReceipts
!=
0
&&
txCount
>
500
/
15
{
return
EthGetBlockReceipts
return
EthGetBlockReceipts
}
}
if
available
&
ParityGetBlockReceipts
!=
0
&&
txCount
>
500
/
15
{
return
ParityGetBlockReceipts
}
return
EthGetTransactionReceiptBatch
return
EthGetTransactionReceiptBatch
}
else
if
kind
==
RPCKindQuickNode
{
}
else
if
kind
==
RPCKindQuickNode
{
if
available
&
DebugGetRawReceipts
!=
0
{
if
available
&
DebugGetRawReceipts
!=
0
{
...
@@ -298,18 +302,20 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc
...
@@ -298,18 +302,20 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc
if
available
&
EthGetBlockReceipts
!=
0
&&
txCount
>
59
/
2
{
if
available
&
EthGetBlockReceipts
!=
0
&&
txCount
>
59
/
2
{
return
EthGetBlockReceipts
return
EthGetBlockReceipts
}
}
if
available
&
ParityGetBlockReceipts
!=
0
&&
txCount
>
59
/
2
{
return
ParityGetBlockReceipts
}
return
EthGetTransactionReceiptBatch
return
EthGetTransactionReceiptBatch
}
}
// otherwise just find the first available method
// in order of preference (based on cost): check available methods
x
:=
ReceiptsFetchingMethod
(
1
)
if
available
&
AlchemyGetTransactionReceipts
!=
0
{
for
x
!=
0
{
return
AlchemyGetTransactionReceipts
if
available
&
x
!=
0
{
}
return
x
if
available
&
DebugGetRawReceipts
!=
0
{
}
return
DebugGetRawReceipts
x
<<=
1
}
if
available
&
EthGetBlockReceipts
!=
0
{
return
EthGetBlockReceipts
}
if
available
&
ParityGetBlockReceipts
!=
0
{
return
ParityGetBlockReceipts
}
}
// otherwise fall back on per-tx fetching
// otherwise fall back on per-tx fetching
return
EthGetTransactionReceiptBatch
return
EthGetTransactionReceiptBatch
...
@@ -415,6 +421,7 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
...
@@ -415,6 +421,7 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
if
len
(
rawReceipts
)
==
len
(
job
.
txHashes
)
{
if
len
(
rawReceipts
)
==
len
(
job
.
txHashes
)
{
result
=
make
([]
*
types
.
Receipt
,
len
(
rawReceipts
))
result
=
make
([]
*
types
.
Receipt
,
len
(
rawReceipts
))
totalIndex
:=
uint
(
0
)
totalIndex
:=
uint
(
0
)
prevCumulativeGasUsed
:=
uint64
(
0
)
for
i
,
r
:=
range
rawReceipts
{
for
i
,
r
:=
range
rawReceipts
{
var
x
types
.
Receipt
var
x
types
.
Receipt
_
=
x
.
UnmarshalBinary
(
r
)
// safe to ignore, we verify receipts against the receipts hash later
_
=
x
.
UnmarshalBinary
(
r
)
// safe to ignore, we verify receipts against the receipts hash later
...
@@ -422,6 +429,9 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
...
@@ -422,6 +429,9 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
x
.
BlockHash
=
job
.
block
.
Hash
x
.
BlockHash
=
job
.
block
.
Hash
x
.
BlockNumber
=
new
(
big
.
Int
)
.
SetUint64
(
job
.
block
.
Number
)
x
.
BlockNumber
=
new
(
big
.
Int
)
.
SetUint64
(
job
.
block
.
Number
)
x
.
TransactionIndex
=
uint
(
i
)
x
.
TransactionIndex
=
uint
(
i
)
x
.
GasUsed
=
x
.
CumulativeGasUsed
-
prevCumulativeGasUsed
// contract address meta-data is not computed.
prevCumulativeGasUsed
=
x
.
CumulativeGasUsed
for
_
,
l
:=
range
x
.
Logs
{
for
_
,
l
:=
range
x
.
Logs
{
l
.
BlockNumber
=
job
.
block
.
Number
l
.
BlockNumber
=
job
.
block
.
Number
l
.
TxHash
=
x
.
TxHash
l
.
TxHash
=
x
.
TxHash
...
...
op-node/sources/receipts_test.go
0 → 100644
View file @
46769845
package
sources
import
(
"context"
"encoding/json"
"fmt"
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
type
ethBackend
struct
{
*
mock
.
Mock
}
func
(
b
*
ethBackend
)
GetBlockByHash
(
id
common
.
Hash
,
fullTxs
bool
)
(
*
rpcBlock
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"eth_getBlockByHash"
,
id
,
fullTxs
)
return
out
[
0
]
.
(
*
rpcBlock
),
nil
}
func
(
b
*
ethBackend
)
GetTransactionReceipt
(
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"eth_getTransactionReceipt"
,
txHash
)
return
out
[
0
]
.
(
*
types
.
Receipt
),
*
out
[
1
]
.
(
*
error
)
}
func
(
b
*
ethBackend
)
GetBlockReceipts
(
id
string
)
([]
*
types
.
Receipt
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"eth_getBlockReceipts"
,
id
)
return
out
[
0
]
.
([]
*
types
.
Receipt
),
*
out
[
1
]
.
(
*
error
)
}
type
alchemyBackend
struct
{
*
mock
.
Mock
}
func
(
b
*
alchemyBackend
)
GetTransactionReceipts
(
p
blockHashParameter
)
(
*
receiptsWrapper
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"alchemy_getTransactionReceipts"
,
p
.
BlockHash
.
String
())
return
&
receiptsWrapper
{
Receipts
:
out
[
0
]
.
([]
*
types
.
Receipt
)},
*
out
[
1
]
.
(
*
error
)
}
type
debugBackend
struct
{
*
mock
.
Mock
}
func
(
b
*
debugBackend
)
GetRawReceipts
(
id
string
)
([]
hexutil
.
Bytes
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"debug_getRawReceipts"
,
id
)
return
out
[
0
]
.
([]
hexutil
.
Bytes
),
*
out
[
1
]
.
(
*
error
)
}
type
parityBackend
struct
{
*
mock
.
Mock
}
func
(
b
*
parityBackend
)
GetBlockReceipts
(
id
string
)
([]
*
types
.
Receipt
,
error
)
{
out
:=
b
.
Mock
.
MethodCalled
(
"parity_getBlockReceipts"
,
id
)
return
out
[
0
]
.
([]
*
types
.
Receipt
),
*
out
[
1
]
.
(
*
error
)
}
type
ReceiptsRequest
struct
{
method
ReceiptsFetchingMethod
result
[]
*
types
.
Receipt
err
error
}
type
methodNotFoundError
struct
{
method
string
}
func
(
e
*
methodNotFoundError
)
ErrorCode
()
int
{
return
-
32601
}
func
(
e
*
methodNotFoundError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"the method %s does not exist/is not available"
,
e
.
method
)
}
// ReceiptsTestCase runs through a series of receipt fetching RPC requests with mocked results
// to test the prioritization/fallback logic of the receipt fetching in the EthClient.
type
ReceiptsTestCase
struct
{
name
string
providerKind
RPCProviderKind
setup
func
(
t
*
testing
.
T
)
(
*
rpcBlock
,
[]
ReceiptsRequest
)
}
func
(
tc
*
ReceiptsTestCase
)
Run
(
t
*
testing
.
T
)
{
srv
:=
rpc
.
NewServer
()
defer
srv
.
Stop
()
m
:=
&
mock
.
Mock
{}
require
.
NoError
(
t
,
srv
.
RegisterName
(
"eth"
,
&
ethBackend
{
Mock
:
m
}))
require
.
NoError
(
t
,
srv
.
RegisterName
(
"alchemy"
,
&
alchemyBackend
{
Mock
:
m
}))
require
.
NoError
(
t
,
srv
.
RegisterName
(
"debug"
,
&
debugBackend
{
Mock
:
m
}))
require
.
NoError
(
t
,
srv
.
RegisterName
(
"parity"
,
&
parityBackend
{
Mock
:
m
}))
block
,
requests
:=
tc
.
setup
(
t
)
// always expect a block request to fetch txs and receipts root hash etc.
m
.
On
(
"eth_getBlockByHash"
,
block
.
Hash
,
true
)
.
Once
()
.
Return
(
block
)
for
_
,
reqData
:=
range
requests
{
req
:=
reqData
// depending on the method, expect to serve receipts by request(s)
switch
req
.
method
{
case
EthGetTransactionReceiptBatch
:
for
i
,
tx
:=
range
block
.
Transactions
{
m
.
On
(
"eth_getTransactionReceipt"
,
tx
.
Hash
())
.
Once
()
.
Return
(
req
.
result
[
i
],
&
req
.
err
)
}
case
AlchemyGetTransactionReceipts
:
m
.
On
(
"alchemy_getTransactionReceipts"
,
block
.
Hash
.
String
())
.
Once
()
.
Return
(
req
.
result
,
&
req
.
err
)
case
DebugGetRawReceipts
:
var
raw
[]
hexutil
.
Bytes
for
_
,
r
:=
range
req
.
result
{
data
,
err
:=
r
.
MarshalBinary
()
require
.
NoError
(
t
,
err
)
raw
=
append
(
raw
,
data
)
}
m
.
On
(
"debug_getRawReceipts"
,
block
.
Hash
.
String
())
.
Once
()
.
Return
(
raw
,
&
req
.
err
)
case
ParityGetBlockReceipts
:
m
.
On
(
"parity_getBlockReceipts"
,
block
.
Hash
.
String
())
.
Once
()
.
Return
(
req
.
result
,
&
req
.
err
)
case
EthGetBlockReceipts
:
m
.
On
(
"eth_getBlockReceipts"
,
block
.
Hash
.
String
())
.
Once
()
.
Return
(
req
.
result
,
&
req
.
err
)
default
:
t
.
Fatalf
(
"unrecognized request method: %d"
,
uint64
(
req
.
method
))
}
}
cl
:=
rpc
.
DialInProc
(
srv
)
testCfg
:=
&
EthClientConfig
{
// receipts and transactions are cached per block
ReceiptsCacheSize
:
1000
,
TransactionsCacheSize
:
1000
,
HeadersCacheSize
:
1000
,
PayloadsCacheSize
:
1000
,
MaxRequestsPerBatch
:
20
,
MaxConcurrentRequests
:
10
,
TrustRPC
:
false
,
MustBePostMerge
:
false
,
RPCProviderKind
:
tc
.
providerKind
,
}
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
ethCl
,
err
:=
NewEthClient
(
client
.
NewBaseRPCClient
(
cl
),
logger
,
nil
,
testCfg
)
require
.
NoError
(
t
,
err
)
defer
ethCl
.
Close
()
for
i
,
req
:=
range
requests
{
info
,
result
,
err
:=
ethCl
.
FetchReceipts
(
context
.
Background
(),
block
.
Hash
)
if
err
==
nil
{
require
.
Nil
(
t
,
req
.
err
,
"error"
)
require
.
Equal
(
t
,
block
.
Hash
,
info
.
Hash
(),
fmt
.
Sprintf
(
"req %d blockhash"
,
i
))
expectedJson
,
err
:=
json
.
MarshalIndent
(
req
.
result
,
""
,
" "
)
require
.
NoError
(
t
,
err
)
gotJson
,
err
:=
json
.
MarshalIndent
(
result
,
""
,
" "
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
string
(
expectedJson
),
string
(
gotJson
),
fmt
.
Sprintf
(
"req %d result"
,
i
))
}
else
{
require
.
NotNil
(
t
,
req
.
err
,
"error"
)
require
.
Equal
(
t
,
req
.
err
.
Error
(),
err
.
Error
(),
fmt
.
Sprintf
(
"req %d err"
,
i
))
}
}
m
.
AssertExpectations
(
t
)
}
func
randomRpcBlockAndReceipts
(
rng
*
rand
.
Rand
,
txCount
uint64
)
(
*
rpcBlock
,
[]
*
types
.
Receipt
)
{
block
,
receipts
:=
testutils
.
RandomBlock
(
rng
,
txCount
)
return
&
rpcBlock
{
rpcHeader
:
rpcHeader
{
ParentHash
:
block
.
ParentHash
(),
UncleHash
:
block
.
UncleHash
(),
Coinbase
:
block
.
Coinbase
(),
Root
:
block
.
Root
(),
TxHash
:
block
.
TxHash
(),
ReceiptHash
:
block
.
ReceiptHash
(),
Bloom
:
eth
.
Bytes256
(
block
.
Bloom
()),
Difficulty
:
*
(
*
hexutil
.
Big
)(
block
.
Difficulty
()),
Number
:
hexutil
.
Uint64
(
block
.
NumberU64
()),
GasLimit
:
hexutil
.
Uint64
(
block
.
GasLimit
()),
GasUsed
:
hexutil
.
Uint64
(
block
.
GasUsed
()),
Time
:
hexutil
.
Uint64
(
block
.
Time
()),
Extra
:
hexutil
.
Bytes
(
block
.
Extra
()),
MixDigest
:
block
.
MixDigest
(),
Nonce
:
types
.
EncodeNonce
(
block
.
Nonce
()),
BaseFee
:
(
*
hexutil
.
Big
)(
block
.
BaseFee
()),
Hash
:
block
.
Hash
(),
},
Transactions
:
block
.
Transactions
(),
},
receipts
}
func
TestEthClient_FetchReceipts
(
t
*
testing
.
T
)
{
// Helper to quickly define the test case requests scenario:
// each method fails to fetch the receipts, except the last
fallbackCase
:=
func
(
txCount
uint64
,
methods
...
ReceiptsFetchingMethod
)
func
(
t
*
testing
.
T
)
(
*
rpcBlock
,
[]
ReceiptsRequest
)
{
return
func
(
t
*
testing
.
T
)
(
*
rpcBlock
,
[]
ReceiptsRequest
)
{
block
,
receipts
:=
randomRpcBlockAndReceipts
(
rand
.
New
(
rand
.
NewSource
(
123
)),
txCount
)
// zero out the data we don't want to verify
for
_
,
r
:=
range
receipts
{
r
.
ContractAddress
=
common
.
Address
{}
}
var
out
[]
ReceiptsRequest
for
_
,
m
:=
range
methods
{
out
=
append
(
out
,
ReceiptsRequest
{
method
:
m
,
})
}
// all but the last request fail to fetch receipts
for
i
:=
0
;
i
<
len
(
out
)
-
1
;
i
++
{
out
[
i
]
.
result
=
nil
out
[
i
]
.
err
=
new
(
methodNotFoundError
)
}
// last request fetches receipts
out
[
len
(
out
)
-
1
]
.
result
=
receipts
return
block
,
out
}
}
testCases
:=
[]
ReceiptsTestCase
{
{
name
:
"alchemy"
,
providerKind
:
RPCKindAlchemy
,
setup
:
fallbackCase
(
30
,
AlchemyGetTransactionReceipts
),
},
{
name
:
"alchemy fallback 1"
,
providerKind
:
RPCKindAlchemy
,
setup
:
fallbackCase
(
40
,
AlchemyGetTransactionReceipts
,
EthGetBlockReceipts
),
},
{
name
:
"alchemy low tx count cost saving"
,
providerKind
:
RPCKindAlchemy
,
// when it's cheaper to fetch individual receipts than the alchemy-bundled receipts we change methods.
setup
:
fallbackCase
(
5
,
EthGetTransactionReceiptBatch
),
},
{
name
:
"quicknode"
,
providerKind
:
RPCKindQuickNode
,
setup
:
fallbackCase
(
30
,
DebugGetRawReceipts
),
},
{
name
:
"quicknode fallback 1"
,
providerKind
:
RPCKindQuickNode
,
setup
:
fallbackCase
(
30
,
DebugGetRawReceipts
,
EthGetBlockReceipts
,
),
},
{
name
:
"quicknode low tx count cost saving"
,
providerKind
:
RPCKindQuickNode
,
// when it's cheaper to fetch individual receipts than the alchemy-bundled receipts we change methods.
setup
:
fallbackCase
(
5
,
DebugGetRawReceipts
,
EthGetTransactionReceiptBatch
),
},
{
name
:
"infura"
,
providerKind
:
RPCKindInfura
,
setup
:
fallbackCase
(
4
,
EthGetTransactionReceiptBatch
),
},
{
name
:
"nethermind"
,
providerKind
:
RPCKindNethermind
,
setup
:
fallbackCase
(
4
,
ParityGetBlockReceipts
),
// uses parity namespace method
},
{
name
:
"geth with debug rpc"
,
providerKind
:
RPCKindDebugGeth
,
setup
:
fallbackCase
(
4
,
DebugGetRawReceipts
),
},
{
name
:
"erigon"
,
providerKind
:
RPCKindErigon
,
setup
:
fallbackCase
(
4
,
EthGetBlockReceipts
),
},
{
name
:
"basic"
,
providerKind
:
RPCKindBasic
,
setup
:
fallbackCase
(
4
,
EthGetTransactionReceiptBatch
),
},
{
name
:
"any discovers alchemy"
,
providerKind
:
RPCKindAny
,
setup
:
fallbackCase
(
4
,
AlchemyGetTransactionReceipts
),
},
{
name
:
"any discovers parity"
,
providerKind
:
RPCKindAny
,
// fallback through the least priority method: parity (nethermind supports this still)
setup
:
fallbackCase
(
4
,
AlchemyGetTransactionReceipts
,
DebugGetRawReceipts
,
EthGetBlockReceipts
,
ParityGetBlockReceipts
,
),
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
name
,
tc
.
Run
)
}
}
op-node/testutils/random.go
View file @
46769845
...
@@ -5,6 +5,10 @@ import (
...
@@ -5,6 +5,10 @@ import (
"math/big"
"math/big"
"math/rand"
"math/rand"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
...
@@ -90,3 +94,139 @@ func NextRandomL2Ref(rng *rand.Rand, l2BlockTime uint64, parent eth.L2BlockRef,
...
@@ -90,3 +94,139 @@ func NextRandomL2Ref(rng *rand.Rand, l2BlockTime uint64, parent eth.L2BlockRef,
SequenceNumber
:
seq
,
SequenceNumber
:
seq
,
}
}
}
}
func
InsecureRandomKey
(
rng
*
rand
.
Rand
)
*
ecdsa
.
PrivateKey
{
key
,
err
:=
ecdsa
.
GenerateKey
(
crypto
.
S256
(),
rng
)
if
err
!=
nil
{
panic
(
err
)
}
return
key
}
func
RandomLog
(
rng
*
rand
.
Rand
)
*
types
.
Log
{
topics
:=
make
([]
common
.
Hash
,
rng
.
Intn
(
3
))
for
i
:=
0
;
i
<
len
(
topics
);
i
++
{
topics
[
i
]
=
RandomHash
(
rng
)
}
return
&
types
.
Log
{
Address
:
RandomAddress
(
rng
),
Topics
:
topics
,
Data
:
RandomData
(
rng
,
rng
.
Intn
(
1000
)),
BlockNumber
:
0
,
TxHash
:
common
.
Hash
{},
TxIndex
:
0
,
BlockHash
:
common
.
Hash
{},
Index
:
0
,
Removed
:
false
,
}
}
func
RandomTo
(
rng
*
rand
.
Rand
)
*
common
.
Address
{
if
rng
.
Intn
(
2
)
==
0
{
return
nil
}
to
:=
RandomAddress
(
rng
)
return
&
to
}
func
RandomTx
(
rng
*
rand
.
Rand
,
baseFee
*
big
.
Int
,
signer
types
.
Signer
)
*
types
.
Transaction
{
gas
:=
params
.
TxGas
+
uint64
(
rng
.
Int63n
(
2
_000_000
))
key
:=
InsecureRandomKey
(
rng
)
tip
:=
big
.
NewInt
(
rng
.
Int63n
(
10
*
params
.
GWei
))
tx
,
err
:=
types
.
SignNewTx
(
key
,
signer
,
&
types
.
DynamicFeeTx
{
ChainID
:
signer
.
ChainID
(),
Nonce
:
rng
.
Uint64
(),
GasTipCap
:
tip
,
GasFeeCap
:
new
(
big
.
Int
)
.
Add
(
baseFee
,
tip
),
Gas
:
gas
,
To
:
RandomTo
(
rng
),
Value
:
RandomETH
(
rng
,
10
),
Data
:
RandomData
(
rng
,
rng
.
Intn
(
1000
)),
AccessList
:
nil
,
})
if
err
!=
nil
{
panic
(
err
)
}
return
tx
}
func
RandomReceipt
(
rng
*
rand
.
Rand
,
signer
types
.
Signer
,
tx
*
types
.
Transaction
,
txIndex
uint64
,
cumulativeGasUsed
uint64
)
*
types
.
Receipt
{
gasUsed
:=
params
.
TxGas
+
uint64
(
rng
.
Int63n
(
int64
(
tx
.
Gas
()
-
params
.
TxGas
+
1
)))
logs
:=
make
([]
*
types
.
Log
,
rng
.
Intn
(
10
))
for
i
:=
range
logs
{
logs
[
i
]
=
RandomLog
(
rng
)
}
var
contractAddr
common
.
Address
if
tx
.
To
()
==
nil
{
sender
,
err
:=
signer
.
Sender
(
tx
)
if
err
!=
nil
{
panic
(
err
)
}
contractAddr
=
crypto
.
CreateAddress
(
sender
,
tx
.
Nonce
())
}
return
&
types
.
Receipt
{
Type
:
tx
.
Type
(),
Status
:
uint64
(
rng
.
Intn
(
2
)),
CumulativeGasUsed
:
cumulativeGasUsed
+
gasUsed
,
Bloom
:
types
.
Bloom
{},
Logs
:
logs
,
TxHash
:
tx
.
Hash
(),
ContractAddress
:
contractAddr
,
GasUsed
:
gasUsed
,
TransactionIndex
:
uint
(
txIndex
),
}
}
func
RandomHeader
(
rng
*
rand
.
Rand
)
*
types
.
Header
{
return
&
types
.
Header
{
ParentHash
:
RandomHash
(
rng
),
UncleHash
:
types
.
EmptyUncleHash
,
Coinbase
:
RandomAddress
(
rng
),
Root
:
RandomHash
(
rng
),
TxHash
:
types
.
EmptyRootHash
,
ReceiptHash
:
types
.
EmptyRootHash
,
Bloom
:
types
.
Bloom
{},
Difficulty
:
big
.
NewInt
(
0
),
Number
:
big
.
NewInt
(
1
+
rng
.
Int63n
(
100
_000_000
)),
GasLimit
:
0
,
GasUsed
:
0
,
Time
:
uint64
(
rng
.
Int63n
(
2
_000_000_000
)),
Extra
:
RandomData
(
rng
,
rng
.
Intn
(
33
)),
MixDigest
:
common
.
Hash
{},
Nonce
:
types
.
BlockNonce
{},
BaseFee
:
big
.
NewInt
(
rng
.
Int63n
(
300
_000_000_000
)),
}
}
func
RandomBlock
(
rng
*
rand
.
Rand
,
txCount
uint64
)
(
*
types
.
Block
,
[]
*
types
.
Receipt
)
{
header
:=
RandomHeader
(
rng
)
signer
:=
types
.
NewLondonSigner
(
big
.
NewInt
(
rng
.
Int63n
(
1000
)))
txs
:=
make
([]
*
types
.
Transaction
,
0
,
txCount
)
for
i
:=
uint64
(
0
);
i
<
txCount
;
i
++
{
txs
=
append
(
txs
,
RandomTx
(
rng
,
header
.
BaseFee
,
signer
))
}
receipts
:=
make
([]
*
types
.
Receipt
,
0
,
txCount
)
cumulativeGasUsed
:=
uint64
(
0
)
for
i
,
tx
:=
range
txs
{
r
:=
RandomReceipt
(
rng
,
signer
,
tx
,
uint64
(
i
),
cumulativeGasUsed
)
cumulativeGasUsed
+=
r
.
GasUsed
receipts
=
append
(
receipts
,
r
)
}
header
.
GasUsed
=
cumulativeGasUsed
header
.
GasLimit
=
cumulativeGasUsed
+
uint64
(
rng
.
Int63n
(
int64
(
cumulativeGasUsed
)))
block
:=
types
.
NewBlock
(
header
,
txs
,
nil
,
receipts
,
trie
.
NewStackTrie
(
nil
))
logIndex
:=
uint
(
0
)
for
i
,
r
:=
range
receipts
{
r
.
BlockHash
=
block
.
Hash
()
r
.
BlockNumber
=
block
.
Number
()
for
_
,
l
:=
range
r
.
Logs
{
l
.
BlockHash
=
block
.
Hash
()
l
.
BlockNumber
=
block
.
NumberU64
()
l
.
TxIndex
=
uint
(
i
)
l
.
TxHash
=
txs
[
i
]
.
Hash
()
l
.
Index
=
logIndex
logIndex
+=
1
}
}
return
block
,
receipts
}
packages/balance-monitor/package.json
View file @
46769845
{
{
"name"
:
"@eth-optimism/
minimum-balance-agent
"
,
"name"
:
"@eth-optimism/
balance-monitor
"
,
"version"
:
"0.0.1"
,
"version"
:
"0.0.1"
,
"description"
:
"Forta Agent that reports whether certain accounts have fallen below some balance"
,
"description"
:
"Forta Agent that reports whether certain accounts have fallen below some balance"
,
"homepage"
:
"https://github.com/ethereum-optimism/optimism/tree/develop/packages/balance-monitor#readme"
,
"homepage"
:
"https://github.com/ethereum-optimism/optimism/tree/develop/packages/balance-monitor#readme"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment