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
b5665b69
Commit
b5665b69
authored
Jun 05, 2023
by
Andreas Bigger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: Refactor retrying logic to use the op-service backoff client
parent
5960102c
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
14 additions
and
373 deletions
+14
-373
host.go
op-program/host/host.go
+12
-3
prefetcher.go
op-program/host/prefetcher/prefetcher.go
+2
-2
retry.go
op-program/host/prefetcher/retry.go
+0
-136
retry_test.go
op-program/host/prefetcher/retry_test.go
+0
-232
No files found.
op-program/host/host.go
View file @
b5665b69
...
@@ -6,6 +6,7 @@ import (
...
@@ -6,6 +6,7 @@ import (
"fmt"
"fmt"
"io"
"io"
"io/fs"
"io/fs"
"math"
"os"
"os"
"os/exec"
"os/exec"
...
@@ -21,10 +22,13 @@ import (
...
@@ -21,10 +22,13 @@ import (
oppio
"github.com/ethereum-optimism/optimism/op-program/io"
oppio
"github.com/ethereum-optimism/optimism/op-program/io"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum-optimism/optimism/op-program/preimage"
opservice
"github.com/ethereum-optimism/optimism/op-service"
opservice
"github.com/ethereum-optimism/optimism/op-service"
opclient
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
)
)
const
maxAttempts
=
math
.
MaxInt
// Succeed or die trying
type
L2Source
struct
{
type
L2Source
struct
{
*
sources
.
L2Client
*
sources
.
L2Client
*
sources
.
DebugClient
*
sources
.
DebugClient
...
@@ -199,16 +203,21 @@ func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *
...
@@ -199,16 +203,21 @@ func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *
return
nil
,
fmt
.
Errorf
(
"failed to setup L2 RPC: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"failed to setup L2 RPC: %w"
,
err
)
}
}
l1Backoff
:=
opclient
.
NewBackoffClient
(
l1RPC
,
maxAttempts
)
l2Backoff
:=
opclient
.
NewBackoffClient
(
l2RPC
,
maxAttempts
)
l1ClCfg
:=
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
)
l1ClCfg
:=
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
)
l2ClCfg
:=
sources
.
L2ClientDefaultConfig
(
cfg
.
Rollup
,
true
)
l1Cl
,
err
:=
sources
.
NewL1Client
(
l1Backoff
,
logger
,
nil
,
l1ClCfg
)
l1Cl
,
err
:=
sources
.
NewL1Client
(
l1RPC
,
logger
,
nil
,
l1ClCfg
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to create L1 client: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"failed to create L1 client: %w"
,
err
)
}
}
l2Cl
,
err
:=
sources
.
NewL2Client
(
l2RPC
,
logger
,
nil
,
l2ClCfg
)
l2ClCfg
:=
sources
.
L2ClientDefaultConfig
(
cfg
.
Rollup
,
true
)
l2Cl
,
err
:=
sources
.
NewL2Client
(
l2Backoff
,
logger
,
nil
,
l2ClCfg
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to create L2 client: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"failed to create L2 client: %w"
,
err
)
}
}
l2DebugCl
:=
&
L2Source
{
L2Client
:
l2Cl
,
DebugClient
:
sources
.
NewDebugClient
(
l2RPC
.
CallContext
)}
l2DebugCl
:=
&
L2Source
{
L2Client
:
l2Cl
,
DebugClient
:
sources
.
NewDebugClient
(
l2RPC
.
CallContext
)}
return
prefetcher
.
NewPrefetcher
(
logger
,
l1Cl
,
l2DebugCl
,
kv
),
nil
return
prefetcher
.
NewPrefetcher
(
logger
,
l1Cl
,
l2DebugCl
,
kv
),
nil
}
}
...
...
op-program/host/prefetcher/prefetcher.go
View file @
b5665b69
...
@@ -42,8 +42,8 @@ type Prefetcher struct {
...
@@ -42,8 +42,8 @@ type Prefetcher struct {
func
NewPrefetcher
(
logger
log
.
Logger
,
l1Fetcher
L1Source
,
l2Fetcher
L2Source
,
kvStore
kvstore
.
KV
)
*
Prefetcher
{
func
NewPrefetcher
(
logger
log
.
Logger
,
l1Fetcher
L1Source
,
l2Fetcher
L2Source
,
kvStore
kvstore
.
KV
)
*
Prefetcher
{
return
&
Prefetcher
{
return
&
Prefetcher
{
logger
:
logger
,
logger
:
logger
,
l1Fetcher
:
NewRetryingL1Source
(
logger
,
l1Fetcher
)
,
l1Fetcher
:
l1Fetcher
,
l2Fetcher
:
NewRetryingL2Source
(
logger
,
l2Fetcher
)
,
l2Fetcher
:
l2Fetcher
,
kvStore
:
kvStore
,
kvStore
:
kvStore
,
}
}
}
}
...
...
op-program/host/prefetcher/retry.go
deleted
100644 → 0
View file @
5960102c
package
prefetcher
import
(
"context"
"math"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
const
maxAttempts
=
math
.
MaxInt
// Succeed or die trying
type
RetryingL1Source
struct
{
logger
log
.
Logger
source
L1Source
strategy
backoff
.
Strategy
}
func
NewRetryingL1Source
(
logger
log
.
Logger
,
source
L1Source
)
*
RetryingL1Source
{
return
&
RetryingL1Source
{
logger
:
logger
,
source
:
source
,
strategy
:
backoff
.
Exponential
(),
}
}
func
(
s
*
RetryingL1Source
)
InfoByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
{
var
info
eth
.
BlockInfo
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
res
,
err
:=
s
.
source
.
InfoByHash
(
ctx
,
blockHash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to retrieve info"
,
"hash"
,
blockHash
,
"err"
,
err
)
return
err
}
info
=
res
return
nil
})
return
info
,
err
}
func
(
s
*
RetryingL1Source
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
var
info
eth
.
BlockInfo
var
txs
types
.
Transactions
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
i
,
t
,
err
:=
s
.
source
.
InfoAndTxsByHash
(
ctx
,
blockHash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to retrieve l1 info and txs"
,
"hash"
,
blockHash
,
"err"
,
err
)
return
err
}
info
=
i
txs
=
t
return
nil
})
return
info
,
txs
,
err
}
func
(
s
*
RetryingL1Source
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
{
var
info
eth
.
BlockInfo
var
rcpts
types
.
Receipts
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
i
,
r
,
err
:=
s
.
source
.
FetchReceipts
(
ctx
,
blockHash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to fetch receipts"
,
"hash"
,
blockHash
,
"err"
,
err
)
return
err
}
info
=
i
rcpts
=
r
return
nil
})
return
info
,
rcpts
,
err
}
var
_
L1Source
=
(
*
RetryingL1Source
)(
nil
)
type
RetryingL2Source
struct
{
logger
log
.
Logger
source
L2Source
strategy
backoff
.
Strategy
}
func
(
s
*
RetryingL2Source
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
var
info
eth
.
BlockInfo
var
txs
types
.
Transactions
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
i
,
t
,
err
:=
s
.
source
.
InfoAndTxsByHash
(
ctx
,
blockHash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to retrieve l2 info and txs"
,
"hash"
,
blockHash
,
"err"
,
err
)
return
err
}
info
=
i
txs
=
t
return
nil
})
return
info
,
txs
,
err
}
func
(
s
*
RetryingL2Source
)
NodeByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
([]
byte
,
error
)
{
var
node
[]
byte
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
n
,
err
:=
s
.
source
.
NodeByHash
(
ctx
,
hash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to retrieve node"
,
"hash"
,
hash
,
"err"
,
err
)
return
err
}
node
=
n
return
nil
})
return
node
,
err
}
func
(
s
*
RetryingL2Source
)
CodeByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
([]
byte
,
error
)
{
var
code
[]
byte
err
:=
backoff
.
DoCtx
(
ctx
,
maxAttempts
,
s
.
strategy
,
func
()
error
{
c
,
err
:=
s
.
source
.
CodeByHash
(
ctx
,
hash
)
if
err
!=
nil
{
s
.
logger
.
Warn
(
"Failed to retrieve code"
,
"hash"
,
hash
,
"err"
,
err
)
return
err
}
code
=
c
return
nil
})
return
code
,
err
}
func
NewRetryingL2Source
(
logger
log
.
Logger
,
source
L2Source
)
*
RetryingL2Source
{
return
&
RetryingL2Source
{
logger
:
logger
,
source
:
source
,
strategy
:
backoff
.
Exponential
(),
}
}
var
_
L2Source
=
(
*
RetryingL2Source
)(
nil
)
op-program/host/prefetcher/retry_test.go
deleted
100644 → 0
View file @
5960102c
package
prefetcher
import
(
"context"
"errors"
"testing"
"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-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func
TestRetryingL1Source
(
t
*
testing
.
T
)
{
ctx
:=
context
.
Background
()
hash
:=
common
.
Hash
{
0xab
}
info
:=
&
testutils
.
MockBlockInfo
{
InfoHash
:
hash
}
// The mock really doesn't like returning nil for a eth.BlockInfo so return a value we expect to be ignored instead
wrongInfo
:=
&
testutils
.
MockBlockInfo
{
InfoHash
:
common
.
Hash
{
0x99
}}
txs
:=
types
.
Transactions
{
&
types
.
Transaction
{},
}
rcpts
:=
types
.
Receipts
{
&
types
.
Receipt
{},
}
t
.
Run
(
"InfoByHash Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectInfoByHash
(
hash
,
info
,
nil
)
result
,
err
:=
source
.
InfoByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
result
)
})
t
.
Run
(
"InfoByHash Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectInfoByHash
(
hash
,
wrongInfo
,
expectedErr
)
mock
.
ExpectInfoByHash
(
hash
,
info
,
nil
)
result
,
err
:=
source
.
InfoByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
result
)
})
t
.
Run
(
"InfoAndTxsByHash Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
info
,
txs
,
nil
)
actualInfo
,
actualTxs
,
err
:=
source
.
InfoAndTxsByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
txs
,
actualTxs
)
})
t
.
Run
(
"InfoAndTxsByHash Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
wrongInfo
,
nil
,
expectedErr
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
info
,
txs
,
nil
)
actualInfo
,
actualTxs
,
err
:=
source
.
InfoAndTxsByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
txs
,
actualTxs
)
})
t
.
Run
(
"FetchReceipts Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectFetchReceipts
(
hash
,
info
,
rcpts
,
nil
)
actualInfo
,
actualRcpts
,
err
:=
source
.
FetchReceipts
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
rcpts
,
actualRcpts
)
})
t
.
Run
(
"FetchReceipts Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL1Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectFetchReceipts
(
hash
,
wrongInfo
,
nil
,
expectedErr
)
mock
.
ExpectFetchReceipts
(
hash
,
info
,
rcpts
,
nil
)
actualInfo
,
actualRcpts
,
err
:=
source
.
FetchReceipts
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
rcpts
,
actualRcpts
)
})
}
func
createL1Source
(
t
*
testing
.
T
)
(
*
RetryingL1Source
,
*
testutils
.
MockL1Source
)
{
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
mock
:=
&
testutils
.
MockL1Source
{}
source
:=
NewRetryingL1Source
(
logger
,
mock
)
// Avoid sleeping in tests by using a fixed backoff strategy with no delay
source
.
strategy
=
backoff
.
Fixed
(
0
)
return
source
,
mock
}
func
TestRetryingL2Source
(
t
*
testing
.
T
)
{
ctx
:=
context
.
Background
()
hash
:=
common
.
Hash
{
0xab
}
info
:=
&
testutils
.
MockBlockInfo
{
InfoHash
:
hash
}
// The mock really doesn't like returning nil for a eth.BlockInfo so return a value we expect to be ignored instead
wrongInfo
:=
&
testutils
.
MockBlockInfo
{
InfoHash
:
common
.
Hash
{
0x99
}}
txs
:=
types
.
Transactions
{
&
types
.
Transaction
{},
}
data
:=
[]
byte
{
1
,
2
,
3
,
4
,
5
}
t
.
Run
(
"InfoAndTxsByHash Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
info
,
txs
,
nil
)
actualInfo
,
actualTxs
,
err
:=
source
.
InfoAndTxsByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
txs
,
actualTxs
)
})
t
.
Run
(
"InfoAndTxsByHash Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
wrongInfo
,
nil
,
expectedErr
)
mock
.
ExpectInfoAndTxsByHash
(
hash
,
info
,
txs
,
nil
)
actualInfo
,
actualTxs
,
err
:=
source
.
InfoAndTxsByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
info
,
actualInfo
)
require
.
Equal
(
t
,
txs
,
actualTxs
)
})
t
.
Run
(
"NodeByHash Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectNodeByHash
(
hash
,
data
,
nil
)
actual
,
err
:=
source
.
NodeByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
data
,
actual
)
})
t
.
Run
(
"NodeByHash Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectNodeByHash
(
hash
,
nil
,
expectedErr
)
mock
.
ExpectNodeByHash
(
hash
,
data
,
nil
)
actual
,
err
:=
source
.
NodeByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
data
,
actual
)
})
t
.
Run
(
"CodeByHash Success"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
mock
.
ExpectCodeByHash
(
hash
,
data
,
nil
)
actual
,
err
:=
source
.
CodeByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
data
,
actual
)
})
t
.
Run
(
"CodeByHash Error"
,
func
(
t
*
testing
.
T
)
{
source
,
mock
:=
createL2Source
(
t
)
defer
mock
.
AssertExpectations
(
t
)
expectedErr
:=
errors
.
New
(
"boom"
)
mock
.
ExpectCodeByHash
(
hash
,
nil
,
expectedErr
)
mock
.
ExpectCodeByHash
(
hash
,
data
,
nil
)
actual
,
err
:=
source
.
CodeByHash
(
ctx
,
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
data
,
actual
)
})
}
func
createL2Source
(
t
*
testing
.
T
)
(
*
RetryingL2Source
,
*
MockL2Source
)
{
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
mock
:=
&
MockL2Source
{}
source
:=
NewRetryingL2Source
(
logger
,
mock
)
// Avoid sleeping in tests by using a fixed backoff strategy with no delay
source
.
strategy
=
backoff
.
Fixed
(
0
)
return
source
,
mock
}
type
MockL2Source
struct
{
mock
.
Mock
}
func
(
m
*
MockL2Source
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
out
:=
m
.
Mock
.
MethodCalled
(
"InfoAndTxsByHash"
,
blockHash
)
return
out
[
0
]
.
(
eth
.
BlockInfo
),
out
[
1
]
.
(
types
.
Transactions
),
*
out
[
2
]
.
(
*
error
)
}
func
(
m
*
MockL2Source
)
NodeByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
([]
byte
,
error
)
{
out
:=
m
.
Mock
.
MethodCalled
(
"NodeByHash"
,
hash
)
return
out
[
0
]
.
([]
byte
),
*
out
[
1
]
.
(
*
error
)
}
func
(
m
*
MockL2Source
)
CodeByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
([]
byte
,
error
)
{
out
:=
m
.
Mock
.
MethodCalled
(
"CodeByHash"
,
hash
)
return
out
[
0
]
.
([]
byte
),
*
out
[
1
]
.
(
*
error
)
}
func
(
m
*
MockL2Source
)
ExpectInfoAndTxsByHash
(
blockHash
common
.
Hash
,
info
eth
.
BlockInfo
,
txs
types
.
Transactions
,
err
error
)
{
m
.
Mock
.
On
(
"InfoAndTxsByHash"
,
blockHash
)
.
Once
()
.
Return
(
info
,
txs
,
&
err
)
}
func
(
m
*
MockL2Source
)
ExpectNodeByHash
(
hash
common
.
Hash
,
node
[]
byte
,
err
error
)
{
m
.
Mock
.
On
(
"NodeByHash"
,
hash
)
.
Once
()
.
Return
(
node
,
&
err
)
}
func
(
m
*
MockL2Source
)
ExpectCodeByHash
(
hash
common
.
Hash
,
code
[]
byte
,
err
error
)
{
m
.
Mock
.
On
(
"CodeByHash"
,
hash
)
.
Once
()
.
Return
(
code
,
&
err
)
}
var
_
L2Source
=
(
*
MockL2Source
)(
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