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
9f62a1f8
Unverified
Commit
9f62a1f8
authored
Apr 13, 2023
by
mergify[bot]
Committed by
GitHub
Apr 13, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into aj/fpp-compute-output-root
parents
08d23701
a6e2b97f
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
523 additions
and
133 deletions
+523
-133
blocktime_test.go
op-e2e/actions/blocktime_test.go
+3
-3
batching.go
op-node/sources/batching.go
+24
-4
batching_test.go
op-node/sources/batching_test.go
+81
-7
receipts.go
op-node/sources/receipts.go
+1
-0
cache.go
op-program/client/l1/cache.go
+63
-0
cache_test.go
op-program/client/l1/cache_test.go
+71
-0
client_test.go
op-program/client/l1/client_test.go
+1
-43
stub_oracle_test.go
op-program/client/l1/stub_oracle_test.go
+54
-0
cache.go
op-program/client/l2/cache.go
+60
-0
cache_test.go
op-program/client/l2/cache_test.go
+67
-0
db_test.go
op-program/client/l2/db_test.go
+0
-48
engine_backend_test.go
op-program/client/l2/engine_backend_test.go
+1
-26
stub_oracle_test.go
op-program/client/l2/stub_oracle_test.go
+94
-0
l1.go
op-program/host/l1/l1.go
+1
-1
l2.go
op-program/host/l2/l2.go
+2
-1
No files found.
op-e2e/actions/blocktime_test.go
View file @
9f62a1f8
...
...
@@ -28,12 +28,11 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
signer
:=
types
.
LatestSigner
(
sd
.
L2Cfg
.
Config
)
cl
:=
sequencerEngine
.
EthClient
()
aliceNonce
:=
uint64
(
0
)
// manual nonce management to avoid geth pending-tx nonce non-determinism flakiness
aliceTx
:=
func
()
{
n
,
err
:=
cl
.
PendingNonceAt
(
t
.
Ctx
(),
dp
.
Addresses
.
Alice
)
require
.
NoError
(
t
,
err
)
tx
:=
types
.
MustSignNewTx
(
dp
.
Secrets
.
Alice
,
signer
,
&
types
.
DynamicFeeTx
{
ChainID
:
sd
.
L2Cfg
.
Config
.
ChainID
,
Nonce
:
n
,
Nonce
:
aliceNonce
,
GasTipCap
:
big
.
NewInt
(
2
*
params
.
GWei
),
GasFeeCap
:
new
(
big
.
Int
)
.
Add
(
miner
.
l1Chain
.
CurrentBlock
()
.
BaseFee
,
big
.
NewInt
(
2
*
params
.
GWei
)),
Gas
:
params
.
TxGas
,
...
...
@@ -41,6 +40,7 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
Value
:
e2eutils
.
Ether
(
2
),
})
require
.
NoError
(
gt
,
cl
.
SendTransaction
(
t
.
Ctx
(),
tx
))
aliceNonce
+=
1
}
makeL2BlockWithAliceTx
:=
func
()
{
aliceTx
()
...
...
op-node/sources/batching.go
View file @
9f62a1f8
...
...
@@ -24,6 +24,7 @@ type IterativeBatchCall[K any, V any] struct {
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
)
getBatch
BatchCallContextFn
getSingle
CallContextFn
requestsValues
[]
V
scheduled
chan
rpc
.
BatchElem
...
...
@@ -35,6 +36,7 @@ func NewIterativeBatchCall[K any, V any](
requestsKeys
[]
K
,
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
),
getBatch
BatchCallContextFn
,
getSingle
CallContextFn
,
batchSize
int
)
*
IterativeBatchCall
[
K
,
V
]
{
if
len
(
requestsKeys
)
<
batchSize
{
...
...
@@ -47,6 +49,7 @@ func NewIterativeBatchCall[K any, V any](
out
:=
&
IterativeBatchCall
[
K
,
V
]{
completed
:
0
,
getBatch
:
getBatch
,
getSingle
:
getSingle
,
requestsKeys
:
requestsKeys
,
batchSize
:
batchSize
,
makeRequest
:
makeRequest
,
...
...
@@ -84,6 +87,11 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
ibc
.
resetLock
.
RLock
()
defer
ibc
.
resetLock
.
RUnlock
()
// return early if context is Done
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
}
// collect a batch from the requests channel
batch
:=
make
([]
rpc
.
BatchElem
,
0
,
ibc
.
batchSize
)
// wait for first element
...
...
@@ -119,11 +127,23 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
break
}
if
err
:=
ibc
.
getBatch
(
ctx
,
batch
);
err
!=
nil
{
for
_
,
r
:=
range
batch
{
ibc
.
scheduled
<-
r
if
len
(
batch
)
==
0
{
return
nil
}
if
ibc
.
batchSize
==
1
{
first
:=
batch
[
0
]
if
err
:=
ibc
.
getSingle
(
ctx
,
&
first
.
Result
,
first
.
Method
,
first
.
Args
...
);
err
!=
nil
{
ibc
.
scheduled
<-
first
return
err
}
}
else
{
if
err
:=
ibc
.
getBatch
(
ctx
,
batch
);
err
!=
nil
{
for
_
,
r
:=
range
batch
{
ibc
.
scheduled
<-
r
}
return
fmt
.
Errorf
(
"failed batch-retrieval: %w"
,
err
)
}
return
fmt
.
Errorf
(
"failed batch-retrieval: %w"
,
err
)
}
var
result
error
for
_
,
elem
:=
range
batch
{
...
...
op-node/sources/batching_test.go
View file @
9f62a1f8
...
...
@@ -34,7 +34,8 @@ type batchTestCase struct {
batchSize
int
batchCalls
[]
batchCall
batchCalls
[]
batchCall
singleCalls
[]
elemCall
mock
.
Mock
}
...
...
@@ -53,7 +54,14 @@ func (tc *batchTestCase) GetBatch(ctx context.Context, b []rpc.BatchElem) error
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
}
return
tc
.
Mock
.
MethodCalled
(
"get"
,
b
)
.
Get
(
0
)
.
([]
error
)[
0
]
return
tc
.
Mock
.
MethodCalled
(
"getBatch"
,
b
)
.
Get
(
0
)
.
([]
error
)[
0
]
}
func
(
tc
*
batchTestCase
)
GetSingle
(
ctx
context
.
Context
,
result
any
,
method
string
,
args
...
any
)
error
{
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
}
return
tc
.
Mock
.
MethodCalled
(
"getSingle"
,
(
*
(
result
.
(
*
interface
{})))
.
(
*
string
),
method
,
args
[
0
])
.
Get
(
0
)
.
([]
error
)[
0
]
}
var
mockErr
=
errors
.
New
(
"mockErr"
)
...
...
@@ -64,7 +72,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
keys
[
i
]
=
i
}
make
Mock
:=
func
(
bci
int
,
bc
batchCall
)
func
(
args
mock
.
Arguments
)
{
make
BatchMock
:=
func
(
bc
batchCall
)
func
(
args
mock
.
Arguments
)
{
return
func
(
args
mock
.
Arguments
)
{
batch
:=
args
[
0
]
.
([]
rpc
.
BatchElem
)
for
i
,
elem
:=
range
batch
{
...
...
@@ -83,7 +91,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
}
}
// mock all the results of the batch calls
for
bci
,
bc
:=
range
tc
.
batchCalls
{
for
_
,
bc
:=
range
tc
.
batchCalls
{
var
batch
[]
rpc
.
BatchElem
for
_
,
elem
:=
range
bc
.
elems
{
batch
=
append
(
batch
,
rpc
.
BatchElem
{
...
...
@@ -94,10 +102,30 @@ func (tc *batchTestCase) Run(t *testing.T) {
})
}
if
len
(
bc
.
elems
)
>
0
{
tc
.
On
(
"get"
,
batch
)
.
Once
()
.
Run
(
makeMock
(
bci
,
bc
))
.
Return
([]
error
{
bc
.
rpcErr
})
// wrap to preserve nil as type of error
tc
.
On
(
"getBatch"
,
batch
)
.
Once
()
.
Run
(
makeBatchMock
(
bc
))
.
Return
([]
error
{
bc
.
rpcErr
})
// wrap to preserve nil as type of error
}
}
makeSingleMock
:=
func
(
ec
elemCall
)
func
(
args
mock
.
Arguments
)
{
return
func
(
args
mock
.
Arguments
)
{
result
:=
args
[
0
]
.
(
*
string
)
id
:=
args
[
2
]
.
(
int
)
require
.
Equal
(
t
,
ec
.
id
,
id
,
"element should match expected element"
)
if
ec
.
err
{
*
result
=
""
}
else
{
*
result
=
fmt
.
Sprintf
(
"mock result id %d"
,
id
)
}
}
}
iter
:=
NewIterativeBatchCall
[
int
,
*
string
](
keys
,
makeTestRequest
,
tc
.
GetBatch
,
tc
.
batchSize
)
// mock the results of unbatched calls
for
_
,
ec
:=
range
tc
.
singleCalls
{
var
ret
error
if
ec
.
err
{
ret
=
mockErr
}
tc
.
On
(
"getSingle"
,
new
(
string
),
"testing_foobar"
,
ec
.
id
)
.
Once
()
.
Run
(
makeSingleMock
(
ec
))
.
Return
([]
error
{
ret
})
}
iter
:=
NewIterativeBatchCall
[
int
,
*
string
](
keys
,
makeTestRequest
,
tc
.
GetBatch
,
tc
.
GetSingle
,
tc
.
batchSize
)
for
i
,
bc
:=
range
tc
.
batchCalls
{
ctx
:=
context
.
Background
()
if
bc
.
makeCtx
!=
nil
{
...
...
@@ -116,6 +144,20 @@ func (tc *batchTestCase) Run(t *testing.T) {
}
}
}
for
i
,
ec
:=
range
tc
.
singleCalls
{
ctx
:=
context
.
Background
()
err
:=
iter
.
Fetch
(
ctx
)
if
err
==
io
.
EOF
{
require
.
Equal
(
t
,
i
,
len
(
tc
.
singleCalls
)
-
1
,
"EOF only on last call"
)
}
else
{
require
.
False
(
t
,
iter
.
Complete
())
if
ec
.
err
{
require
.
Error
(
t
,
err
)
}
else
{
require
.
NoError
(
t
,
err
)
}
}
}
require
.
True
(
t
,
iter
.
Complete
(),
"batch iter should be complete after the expected calls"
)
out
,
err
:=
iter
.
Result
()
require
.
NoError
(
t
,
err
)
...
...
@@ -154,6 +196,37 @@ func TestFetchBatched(t *testing.T) {
},
},
},
{
name
:
"single element"
,
items
:
1
,
batchSize
:
4
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
},
},
{
name
:
"unbatched"
,
items
:
4
,
batchSize
:
1
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
false
},
{
id
:
2
,
err
:
false
},
{
id
:
3
,
err
:
false
},
},
},
{
name
:
"unbatched with retry"
,
items
:
4
,
batchSize
:
1
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
true
},
{
id
:
2
,
err
:
false
},
{
id
:
3
,
err
:
false
},
{
id
:
1
,
err
:
false
},
},
},
{
name
:
"split"
,
items
:
5
,
...
...
@@ -240,7 +313,7 @@ func TestFetchBatched(t *testing.T) {
},
{
name
:
"context timeout"
,
items
:
1
,
items
:
2
,
batchSize
:
3
,
batchCalls
:
[]
batchCall
{
{
...
...
@@ -255,6 +328,7 @@ func TestFetchBatched(t *testing.T) {
{
elems
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
false
},
},
err
:
""
,
},
...
...
op-node/sources/receipts.go
View file @
9f62a1f8
...
...
@@ -373,6 +373,7 @@ func (job *receiptsFetchingJob) runFetcher(ctx context.Context) error {
job
.
txHashes
,
makeReceiptRequest
,
job
.
client
.
BatchCallContext
,
job
.
client
.
CallContext
,
job
.
maxBatchSize
,
)
}
...
...
op-program/client/l1/cache.go
0 → 100644
View file @
9f62a1f8
package
l1
import
(
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/hashicorp/golang-lru/v2/simplelru"
)
// Cache size is quite high as retrieving data from the pre-image oracle can be quite expensive
const
cacheSize
=
2000
// CachingOracle is an implementation of Oracle that delegates to another implementation, adding caching of all results
type
CachingOracle
struct
{
oracle
Oracle
blocks
*
simplelru
.
LRU
[
common
.
Hash
,
eth
.
BlockInfo
]
txs
*
simplelru
.
LRU
[
common
.
Hash
,
types
.
Transactions
]
rcpts
*
simplelru
.
LRU
[
common
.
Hash
,
types
.
Receipts
]
}
func
NewCachingOracle
(
oracle
Oracle
)
*
CachingOracle
{
blockLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
eth
.
BlockInfo
](
cacheSize
,
nil
)
txsLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
types
.
Transactions
](
cacheSize
,
nil
)
rcptsLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
types
.
Receipts
](
cacheSize
,
nil
)
return
&
CachingOracle
{
oracle
:
oracle
,
blocks
:
blockLRU
,
txs
:
txsLRU
,
rcpts
:
rcptsLRU
,
}
}
func
(
o
*
CachingOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
block
,
ok
:=
o
.
blocks
.
Get
(
blockHash
)
if
ok
{
return
block
}
block
=
o
.
oracle
.
HeaderByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
return
block
}
func
(
o
*
CachingOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
.
Get
(
blockHash
)
if
ok
{
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
block
,
txs
:=
o
.
oracle
.
TransactionsByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
o
.
txs
.
Add
(
blockHash
,
txs
)
return
block
,
txs
}
func
(
o
*
CachingOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
.
Get
(
blockHash
)
if
ok
{
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
block
,
rcpts
:=
o
.
oracle
.
ReceiptsByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
o
.
rcpts
.
Add
(
blockHash
,
rcpts
)
return
block
,
rcpts
}
op-program/client/l1/cache_test.go
0 → 100644
View file @
9f62a1f8
package
l1
import
(
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/stretchr/testify/require"
)
// Should implement Oracle
var
_
Oracle
=
(
*
CachingOracle
)(
nil
)
func
TestCachingOracle_HeaderByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
:=
testutils
.
RandomBlockInfo
(
rng
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
result
:=
oracle
.
HeaderByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
result
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
result
=
oracle
.
HeaderByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
result
)
}
func
TestCachingOracle_TransactionsByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
,
_
:=
testutils
.
RandomBlock
(
rng
,
3
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
stub
.
txs
[
block
.
Hash
()]
=
block
.
Transactions
()
actualBlock
,
actualTxs
:=
oracle
.
TransactionsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
Equal
(
t
,
block
.
Transactions
(),
actualTxs
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
delete
(
stub
.
txs
,
block
.
Hash
())
actualBlock
,
actualTxs
=
oracle
.
TransactionsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
Equal
(
t
,
block
.
Transactions
(),
actualTxs
)
}
func
TestCachingOracle_ReceiptsByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
,
rcpts
:=
testutils
.
RandomBlock
(
rng
,
3
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
stub
.
rcpts
[
block
.
Hash
()]
=
rcpts
actualBlock
,
actualRcpts
:=
oracle
.
ReceiptsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
EqualValues
(
t
,
rcpts
,
actualRcpts
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
delete
(
stub
.
rcpts
,
block
.
Hash
())
actualBlock
,
actualRcpts
=
oracle
.
ReceiptsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
EqualValues
(
t
,
rcpts
,
actualRcpts
)
}
op-program/client/l1/client_test.go
View file @
9f62a1f8
...
...
@@ -145,54 +145,12 @@ func TestL1BlockRefByNumber(t *testing.T) {
}
func
newClient
(
t
*
testing
.
T
)
(
*
OracleL1Client
,
*
stubOracle
)
{
stub
:=
&
stubOracle
{
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
eth
.
BlockInfo
),
txs
:
make
(
map
[
common
.
Hash
]
types
.
Transactions
),
rcpts
:
make
(
map
[
common
.
Hash
]
types
.
Receipts
),
}
stub
:=
newStubOracle
(
t
)
stub
.
blocks
[
head
.
Hash
()]
=
head
client
:=
NewOracleL1Client
(
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
stub
,
head
.
Hash
())
return
client
,
stub
}
type
stubOracle
struct
{
t
*
testing
.
T
// blocks maps block hash to eth.BlockInfo
blocks
map
[
common
.
Hash
]
eth
.
BlockInfo
// txs maps block hash to transactions
txs
map
[
common
.
Hash
]
types
.
Transactions
// rcpts maps Block hash to receipts
rcpts
map
[
common
.
Hash
]
types
.
Receipts
}
func
(
o
stubOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
info
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown block %s"
,
blockHash
)
}
return
info
}
func
(
o
stubOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown txs %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
func
(
o
stubOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown rcpts %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
func
blockNum
(
num
uint64
)
eth
.
BlockInfo
{
parentNum
:=
num
-
1
return
&
testutils
.
MockBlockInfo
{
...
...
op-program/client/l1/stub_oracle_test.go
0 → 100644
View file @
9f62a1f8
package
l1
import
(
"testing"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type
stubOracle
struct
{
t
*
testing
.
T
// blocks maps block hash to eth.BlockInfo
blocks
map
[
common
.
Hash
]
eth
.
BlockInfo
// txs maps block hash to transactions
txs
map
[
common
.
Hash
]
types
.
Transactions
// rcpts maps Block hash to receipts
rcpts
map
[
common
.
Hash
]
types
.
Receipts
}
func
newStubOracle
(
t
*
testing
.
T
)
*
stubOracle
{
return
&
stubOracle
{
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
eth
.
BlockInfo
),
txs
:
make
(
map
[
common
.
Hash
]
types
.
Transactions
),
rcpts
:
make
(
map
[
common
.
Hash
]
types
.
Receipts
),
}
}
func
(
o
stubOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
info
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown block %s"
,
blockHash
)
}
return
info
}
func
(
o
stubOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown txs %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
func
(
o
stubOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown rcpts %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
op-program/client/l2/cache.go
0 → 100644
View file @
9f62a1f8
package
l2
import
(
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/hashicorp/golang-lru/v2/simplelru"
)
const
blockCacheSize
=
2
_000
const
nodeCacheSize
=
100
_000
const
codeCacheSize
=
10
_000
type
CachingOracle
struct
{
oracle
Oracle
blocks
*
simplelru
.
LRU
[
common
.
Hash
,
*
types
.
Block
]
nodes
*
simplelru
.
LRU
[
common
.
Hash
,
[]
byte
]
codes
*
simplelru
.
LRU
[
common
.
Hash
,
[]
byte
]
}
func
NewCachingOracle
(
oracle
Oracle
)
*
CachingOracle
{
blockLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
*
types
.
Block
](
blockCacheSize
,
nil
)
nodeLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
[]
byte
](
nodeCacheSize
,
nil
)
codeLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
[]
byte
](
codeCacheSize
,
nil
)
return
&
CachingOracle
{
oracle
:
oracle
,
blocks
:
blockLRU
,
nodes
:
nodeLRU
,
codes
:
codeLRU
,
}
}
func
(
o
*
CachingOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
node
,
ok
:=
o
.
nodes
.
Get
(
nodeHash
)
if
ok
{
return
node
}
node
=
o
.
oracle
.
NodeByHash
(
nodeHash
)
o
.
nodes
.
Add
(
nodeHash
,
node
)
return
node
}
func
(
o
*
CachingOracle
)
CodeByHash
(
codeHash
common
.
Hash
)
[]
byte
{
code
,
ok
:=
o
.
codes
.
Get
(
codeHash
)
if
ok
{
return
code
}
code
=
o
.
oracle
.
CodeByHash
(
codeHash
)
o
.
codes
.
Add
(
codeHash
,
code
)
return
code
}
func
(
o
*
CachingOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
.
Get
(
blockHash
)
if
ok
{
return
block
}
block
=
o
.
oracle
.
BlockByHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
return
block
}
op-program/client/l2/cache_test.go
0 → 100644
View file @
9f62a1f8
package
l2
import
(
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// Should be an Oracle implementation
var
_
Oracle
=
(
*
CachingOracle
)(
nil
)
func
TestBlockByHash
(
t
*
testing
.
T
)
{
stub
,
_
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
block
,
_
:=
testutils
.
RandomBlock
(
rng
,
1
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
actual
:=
oracle
.
BlockByHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actual
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
actual
=
oracle
.
BlockByHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actual
)
}
func
TestNodeByHash
(
t
*
testing
.
T
)
{
stub
,
stateStub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
node
:=
[]
byte
{
12
,
3
,
4
}
hash
:=
common
.
Hash
{
0xaa
}
// Initial call retrieves from the stub
stateStub
.
data
[
hash
]
=
node
actual
:=
oracle
.
NodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
// Later calls should retrieve from cache
delete
(
stateStub
.
data
,
hash
)
actual
=
oracle
.
NodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
}
func
TestCodeByHash
(
t
*
testing
.
T
)
{
stub
,
stateStub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
node
:=
[]
byte
{
12
,
3
,
4
}
hash
:=
common
.
Hash
{
0xaa
}
// Initial call retrieves from the stub
stateStub
.
code
[
hash
]
=
node
actual
:=
oracle
.
CodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
// Later calls should retrieve from cache
delete
(
stateStub
.
code
,
hash
)
actual
=
oracle
.
CodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
}
op-program/client/l2/db_test.go
View file @
9f62a1f8
...
...
@@ -194,51 +194,3 @@ func assertStateDataAvailable(t *testing.T, db ethdb.KeyValueStore, l2Genesis *c
require
.
Nil
(
t
,
statedb
.
GetCode
(
unknownAccount
),
"unset account code"
)
require
.
Equal
(
t
,
common
.
Hash
{},
statedb
.
GetCodeHash
(
unknownAccount
),
"unset account code hash"
)
}
func
newStubStateOracle
(
t
*
testing
.
T
)
*
stubStateOracle
{
return
&
stubStateOracle
{
t
:
t
,
data
:
make
(
map
[
common
.
Hash
][]
byte
),
code
:
make
(
map
[
common
.
Hash
][]
byte
),
}
}
type
stubStateOracle
struct
{
t
*
testing
.
T
data
map
[
common
.
Hash
][]
byte
code
map
[
common
.
Hash
][]
byte
}
func
(
o
*
stubStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
data
[
nodeHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for node %v"
,
nodeHash
)
}
return
data
}
func
(
o
*
stubStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
code
[
hash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for code %v"
,
hash
)
}
return
data
}
// kvStateOracle loads data from a source ethdb.KeyValueStore
type
kvStateOracle
struct
{
t
*
testing
.
T
source
ethdb
.
KeyValueStore
}
func
(
o
*
kvStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
val
,
err
:=
o
.
source
.
Get
(
nodeHash
.
Bytes
())
if
err
!=
nil
{
o
.
t
.
Fatalf
(
"error retrieving node %v: %v"
,
nodeHash
,
err
)
}
return
val
}
func
(
o
*
kvStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
return
rawdb
.
ReadCode
(
o
.
source
,
hash
)
}
op-program/client/l2/engine_backend_test.go
View file @
9f62a1f8
...
...
@@ -14,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
...
...
@@ -168,7 +167,7 @@ func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.Cha
genesisBlock
:=
l2Genesis
.
MustCommit
(
db
)
blocks
,
_
:=
core
.
GenerateChain
(
chainCfg
,
genesisBlock
,
consensus
,
db
,
blockCount
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{})
blocks
=
append
([]
*
types
.
Block
{
genesisBlock
},
blocks
...
)
oracle
:=
newStub
BlockOracle
(
t
,
blocks
[
:
headBlockNumber
+
1
],
db
)
oracle
:=
newStub
OracleWithBlocks
(
t
,
blocks
[
:
headBlockNumber
+
1
],
db
)
return
chainCfg
,
blocks
,
oracle
}
...
...
@@ -195,30 +194,6 @@ func createBlock(t *testing.T, chain *OracleBackedL2Chain) *types.Block {
return
blocks
[
0
]
}
type
stubBlockOracle
struct
{
blocks
map
[
common
.
Hash
]
*
types
.
Block
kvStateOracle
}
func
newStubBlockOracle
(
t
*
testing
.
T
,
chain
[]
*
types
.
Block
,
db
ethdb
.
Database
)
*
stubBlockOracle
{
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
,
len
(
chain
))
for
_
,
block
:=
range
chain
{
blocks
[
block
.
Hash
()]
=
block
}
return
&
stubBlockOracle
{
blocks
:
blocks
,
kvStateOracle
:
kvStateOracle
{
t
:
t
,
source
:
db
},
}
}
func
(
o
stubBlockOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"requested unknown block %s"
,
blockHash
)
}
return
block
}
func
TestEngineAPITests
(
t
*
testing
.
T
)
{
test
.
RunEngineAPITests
(
t
,
func
(
t
*
testing
.
T
)
engineapi
.
EngineBackend
{
_
,
chain
:=
setupOracleBackedChain
(
t
,
0
)
...
...
op-program/client/l2/stub_oracle_test.go
0 → 100644
View file @
9f62a1f8
package
l2
import
(
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
)
type
stubBlockOracle
struct
{
t
*
testing
.
T
blocks
map
[
common
.
Hash
]
*
types
.
Block
StateOracle
}
func
newStubOracle
(
t
*
testing
.
T
)
(
*
stubBlockOracle
,
*
stubStateOracle
)
{
stateOracle
:=
newStubStateOracle
(
t
)
blockOracle
:=
stubBlockOracle
{
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
*
types
.
Block
),
StateOracle
:
stateOracle
,
}
return
&
blockOracle
,
stateOracle
}
func
newStubOracleWithBlocks
(
t
*
testing
.
T
,
chain
[]
*
types
.
Block
,
db
ethdb
.
Database
)
*
stubBlockOracle
{
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
,
len
(
chain
))
for
_
,
block
:=
range
chain
{
blocks
[
block
.
Hash
()]
=
block
}
return
&
stubBlockOracle
{
blocks
:
blocks
,
StateOracle
:
&
kvStateOracle
{
t
:
t
,
source
:
db
},
}
}
func
(
o
stubBlockOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"requested unknown block %s"
,
blockHash
)
}
return
block
}
// kvStateOracle loads data from a source ethdb.KeyValueStore
type
kvStateOracle
struct
{
t
*
testing
.
T
source
ethdb
.
KeyValueStore
}
func
(
o
*
kvStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
val
,
err
:=
o
.
source
.
Get
(
nodeHash
.
Bytes
())
if
err
!=
nil
{
o
.
t
.
Fatalf
(
"error retrieving node %v: %v"
,
nodeHash
,
err
)
}
return
val
}
func
(
o
*
kvStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
return
rawdb
.
ReadCode
(
o
.
source
,
hash
)
}
func
newStubStateOracle
(
t
*
testing
.
T
)
*
stubStateOracle
{
return
&
stubStateOracle
{
t
:
t
,
data
:
make
(
map
[
common
.
Hash
][]
byte
),
code
:
make
(
map
[
common
.
Hash
][]
byte
),
}
}
// Stub StateOracle implementation that reads from simple maps
type
stubStateOracle
struct
{
t
*
testing
.
T
data
map
[
common
.
Hash
][]
byte
code
map
[
common
.
Hash
][]
byte
}
func
(
o
*
stubStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
data
[
nodeHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for node %v"
,
nodeHash
)
}
return
data
}
func
(
o
*
stubStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
code
[
hash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for code %v"
,
hash
)
}
return
data
}
op-program/host/l1/l1.go
View file @
9f62a1f8
...
...
@@ -21,6 +21,6 @@ func NewFetchingL1(ctx context.Context, logger log.Logger, cfg *config.Config) (
if
err
!=
nil
{
return
nil
,
err
}
oracle
:=
NewFetchingL1Oracle
(
ctx
,
logger
,
source
)
oracle
:=
cll1
.
NewCachingOracle
(
NewFetchingL1Oracle
(
ctx
,
logger
,
source
)
)
return
cll1
.
NewOracleL1Client
(
logger
,
oracle
,
cfg
.
L1Head
),
err
}
op-program/host/l2/l2.go
View file @
9f62a1f8
...
...
@@ -18,10 +18,11 @@ func NewFetchingEngine(ctx context.Context, logger log.Logger, cfg *config.Confi
if
err
!=
nil
{
return
nil
,
err
}
oracle
,
err
:=
NewFetchingL2Oracle
(
ctx
,
logger
,
cfg
.
L2URL
,
cfg
.
L2Head
)
fetcher
,
err
:=
NewFetchingL2Oracle
(
ctx
,
logger
,
cfg
.
L2URL
,
cfg
.
L2Head
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"connect l2 oracle: %w"
,
err
)
}
oracle
:=
cll2
.
NewCachingOracle
(
fetcher
)
engineBackend
,
err
:=
cll2
.
NewOracleBackedL2Chain
(
logger
,
oracle
,
genesis
,
cfg
.
L2Head
)
if
err
!=
nil
{
...
...
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