Commit 084269f0 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into aj/invalid-root-docs

parents a49ff03f 4cc0f7bf
...@@ -56,8 +56,9 @@ def main(): ...@@ -56,8 +56,9 @@ def main():
deployment_dir = pjoin(contracts_bedrock_dir, 'deployments', 'devnetL1') deployment_dir = pjoin(contracts_bedrock_dir, 'deployments', 'devnetL1')
op_node_dir = pjoin(args.monorepo_dir, 'op-node') op_node_dir = pjoin(args.monorepo_dir, 'op-node')
ops_bedrock_dir = pjoin(monorepo_dir, 'ops-bedrock') ops_bedrock_dir = pjoin(monorepo_dir, 'ops-bedrock')
deploy_config_dir = pjoin(contracts_bedrock_dir, 'deploy-config'), deploy_config_dir = pjoin(contracts_bedrock_dir, 'deploy-config')
devnet_config_path = pjoin(contracts_bedrock_dir, 'deploy-config', 'devnetL1.json') devnet_config_path = pjoin(deploy_config_dir, 'devnetL1.json')
devnet_config_template_path = pjoin(deploy_config_dir, 'devnetL1-template.json')
ops_chain_ops = pjoin(monorepo_dir, 'op-chain-ops') ops_chain_ops = pjoin(monorepo_dir, 'op-chain-ops')
sdk_dir = pjoin(monorepo_dir, 'packages', 'sdk') sdk_dir = pjoin(monorepo_dir, 'packages', 'sdk')
...@@ -69,6 +70,7 @@ def main(): ...@@ -69,6 +70,7 @@ def main():
l1_deployments_path=pjoin(deployment_dir, '.deploy'), l1_deployments_path=pjoin(deployment_dir, '.deploy'),
deploy_config_dir=deploy_config_dir, deploy_config_dir=deploy_config_dir,
devnet_config_path=devnet_config_path, devnet_config_path=devnet_config_path,
devnet_config_template_path=devnet_config_template_path,
op_node_dir=op_node_dir, op_node_dir=op_node_dir,
ops_bedrock_dir=ops_bedrock_dir, ops_bedrock_dir=ops_bedrock_dir,
ops_chain_ops=ops_chain_ops, ops_chain_ops=ops_chain_ops,
...@@ -124,10 +126,16 @@ def deploy_contracts(paths): ...@@ -124,10 +126,16 @@ def deploy_contracts(paths):
'--rpc-url', 'http://127.0.0.1:8545' '--rpc-url', 'http://127.0.0.1:8545'
], env={}, cwd=paths.contracts_bedrock_dir) ], env={}, cwd=paths.contracts_bedrock_dir)
def init_devnet_l1_deploy_config(paths, update_timestamp=False):
deploy_config = read_json(paths.devnet_config_template_path)
if update_timestamp:
deploy_config['l1GenesisBlockTimestamp'] = '{:#x}'.format(int(time.time()))
write_json(paths.devnet_config_path, deploy_config)
def devnet_l1_genesis(paths): def devnet_l1_genesis(paths):
log.info('Generating L1 genesis state') log.info('Generating L1 genesis state')
init_devnet_l1_deploy_config(paths)
geth = subprocess.Popen([ geth = subprocess.Popen([
'geth', '--dev', '--http', '--http.api', 'eth,debug', 'geth', '--dev', '--http', '--http.api', 'eth,debug',
'--verbosity', '4', '--gcmode', 'archive', '--dev.gaslimit', '30000000' '--verbosity', '4', '--gcmode', 'archive', '--dev.gaslimit', '30000000'
...@@ -157,13 +165,13 @@ def devnet_deploy(paths): ...@@ -157,13 +165,13 @@ def devnet_deploy(paths):
if os.path.exists(paths.allocs_path) == False: if os.path.exists(paths.allocs_path) == False:
devnet_l1_genesis(paths) devnet_l1_genesis(paths)
devnet_config_backup = pjoin(paths.devnet_dir, 'devnetL1.json.bak') # It's odd that we want to regenerate the devnetL1.json file with
shutil.copy(paths.devnet_config_path, devnet_config_backup) # an updated timestamp different than the one used in the devnet_l1_genesis
deploy_config = read_json(paths.devnet_config_path) # function. But, without it, CI flakes on this test rather consistently.
deploy_config['l1GenesisBlockTimestamp'] = '{:#x}'.format(int(time.time())) # If someone reads this comment and understands why this is being done, please
write_json(paths.devnet_config_path, deploy_config) # update this comment to explain.
init_devnet_l1_deploy_config(paths, update_timestamp=True)
outfile_l1 = pjoin(paths.devnet_dir, 'genesis-l1.json') outfile_l1 = pjoin(paths.devnet_dir, 'genesis-l1.json')
run_command([ run_command([
'go', 'run', 'cmd/main.go', 'genesis', 'l1', 'go', 'run', 'cmd/main.go', 'genesis', 'l1',
'--deploy-config', paths.devnet_config_path, '--deploy-config', paths.devnet_config_path,
......
...@@ -13,43 +13,6 @@ import ( ...@@ -13,43 +13,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMultipleAlphabetGames(t *testing.T) {
InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys.cfg.L1Deployments, l1Client)
// Start a challenger with the correct alphabet trace
gameFactory.StartChallenger(ctx, sys.NodeEndpoint("l1"), "TowerDefense",
challenger.WithAlphabet("abcdefg"),
challenger.WithPrivKey(sys.cfg.Secrets.Alice),
challenger.WithAgreeProposedOutput(true),
)
game1 := gameFactory.StartAlphabetGame(ctx, "abcxyz")
// Wait for the challenger to respond to the first game
game1.WaitForClaimCount(ctx, 2)
game2 := gameFactory.StartAlphabetGame(ctx, "zyxabc")
// Wait for the challenger to respond to the second game
game2.WaitForClaimCount(ctx, 2)
// Challenger should respond to new claims
game2.Attack(ctx, 1, common.Hash{0xaa})
game2.WaitForClaimCount(ctx, 4)
game1.Defend(ctx, 1, common.Hash{0xaa})
game1.WaitForClaimCount(ctx, 4)
gameDuration := game1.GameDuration(ctx)
sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game1.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game2.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
}
func TestMultipleCannonGames(t *testing.T) { func TestMultipleCannonGames(t *testing.T) {
InitParallel(t) InitParallel(t)
...@@ -106,36 +69,6 @@ func TestMultipleCannonGames(t *testing.T) { ...@@ -106,36 +69,6 @@ func TestMultipleCannonGames(t *testing.T) {
challenger.WaitForGameDataDeletion(ctx, game1, game2) challenger.WaitForGameDataDeletion(ctx, game1, game2)
} }
func TestResolveDisputeGame(t *testing.T) {
InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.cfg.L1Deployments, l1Client)
game := disputeGameFactory.StartAlphabetGame(ctx, "zyxwvut")
require.NotNil(t, game)
gameDuration := game.GameDuration(ctx)
game.WaitForGameStatus(ctx, disputegame.StatusInProgress)
game.StartChallenger(ctx, sys.NodeEndpoint("l1"), "HonestAlice",
challenger.WithAgreeProposedOutput(true),
challenger.WithAlphabet("abcdefg"),
challenger.WithPrivKey(sys.cfg.Secrets.Alice),
)
game.WaitForClaimCount(ctx, 2)
sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
// Challenger should resolve the game now that the clocks have expired.
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
}
func TestChallengerCompleteDisputeGame(t *testing.T) { func TestChallengerCompleteDisputeGame(t *testing.T) {
InitParallel(t) InitParallel(t)
......
...@@ -18,9 +18,10 @@ COPY --from=builder /app/entrypoint.sh /bin/entrypoint.sh ...@@ -18,9 +18,10 @@ COPY --from=builder /app/entrypoint.sh /bin/entrypoint.sh
COPY --from=builder /app/bin/ufm /bin/ufm COPY --from=builder /app/bin/ufm /bin/ufm
RUN apk update && \ RUN apk update && \
apk add ca-certificates && \
chmod +x /bin/entrypoint.sh chmod +x /bin/entrypoint.sh
RUN apk add ca-certificates jq curl bind-tools
VOLUME /etc/ufm VOLUME /etc/ufm
EXPOSE 8080 EXPOSE 8080
......
...@@ -39,12 +39,6 @@ address = "0x0000000000000000000000000000000000000000" ...@@ -39,12 +39,6 @@ address = "0x0000000000000000000000000000000000000000"
private_key = "0000000000000000000000000000000000000000000000000000000000000000" private_key = "0000000000000000000000000000000000000000000000000000000000000000"
# Transaction value in wei # Transaction value in wei
tx_value = 100000000000000 tx_value = 100000000000000
# Gas limit
gas_limit = 21000
# Gas tip cap
gas_tip_cap = 2000000000
# Fee cap
gas_fee_cap = 20000000000
[providers.p1] [providers.p1]
# URL to the RPC provider # URL to the RPC provider
...@@ -52,13 +46,15 @@ url = "http://localhost:8551" ...@@ -52,13 +46,15 @@ url = "http://localhost:8551"
# Read only providers are only used to check for transactions # Read only providers are only used to check for transactions
read_only = true read_only = true
# Interval to poll the provider for expected transactions # Interval to poll the provider for expected transactions
read_interval = "1s" read_interval = "10s"
# Interval to submit new transactions to the provider # Interval to submit new transactions to the provider
send_interval = "5s" send_interval = "30s"
# Wallet to be used for sending transactions # Interval between send transaction when we get "already known" txpool err
wallet = "default" send_transaction_retry_interval = "100ms"
# Network to pool transactions, i.e. providers in the same network will check transactions from each other # Max time to retry
network = "op-goerli" send_transaction_retry_timeout = "5s"
# Interval between each send transaction to the same network
send_transaction_cool_down = "30s"
# Interval between receipt retrieval # Interval between receipt retrieval
receipt_retrieval_interval = "500ms" receipt_retrieval_interval = "500ms"
# Max time to check for receipt # Max time to check for receipt
...@@ -72,13 +68,15 @@ url = "http://localhost:8552" ...@@ -72,13 +68,15 @@ url = "http://localhost:8552"
# Read only providers are only used to check for transactions # Read only providers are only used to check for transactions
read_only = false read_only = false
# Interval to poll the provider for expected transactions # Interval to poll the provider for expected transactions
read_interval = "2s" read_interval = "10s"
# Interval to submit new transactions to the provider # Interval to submit new transactions to the provider
send_interval = "3s" send_interval = "30s"
# Wallet to be used for sending transactions # Interval between send transaction when we get "already known" txpool err
wallet = "default" send_transaction_retry_interval = "100ms"
# Network to pool transactions, i.e. providers in the same network will check transactions from each other # Max time to retry
network = "op-goerli" send_transaction_retry_timeout = "5s"
# Interval between each send transaction to the same network
send_transaction_cool_down = "30s"
# Interval between receipt retrieval # Interval between receipt retrieval
receipt_retrieval_interval = "500ms" receipt_retrieval_interval = "500ms"
# Max time to check for receipt # Max time to check for receipt
......
...@@ -48,10 +48,7 @@ type WalletConfig struct { ...@@ -48,10 +48,7 @@ type WalletConfig struct {
PrivateKey string `toml:"private_key"` PrivateKey string `toml:"private_key"`
// transaction parameters // transaction parameters
TxValue big.Int `toml:"tx_value"` TxValue big.Int `toml:"tx_value"`
GasLimit uint64 `toml:"gas_limit"`
GasTipCap big.Int `toml:"gas_tip_cap"`
GasFeeCap big.Int `toml:"gas_fee_cap"`
} }
type ProviderConfig struct { type ProviderConfig struct {
...@@ -64,6 +61,7 @@ type ProviderConfig struct { ...@@ -64,6 +61,7 @@ type ProviderConfig struct {
SendInterval TOMLDuration `toml:"send_interval"` SendInterval TOMLDuration `toml:"send_interval"`
SendTransactionRetryInterval TOMLDuration `toml:"send_transaction_retry_interval"` SendTransactionRetryInterval TOMLDuration `toml:"send_transaction_retry_interval"`
SendTransactionRetryTimeout TOMLDuration `toml:"send_transaction_retry_timeout"` SendTransactionRetryTimeout TOMLDuration `toml:"send_transaction_retry_timeout"`
SendTransactionCoolDown TOMLDuration `toml:"send_transaction_cool_down"`
ReceiptRetrievalInterval TOMLDuration `toml:"receipt_retrieval_interval"` ReceiptRetrievalInterval TOMLDuration `toml:"receipt_retrieval_interval"`
ReceiptRetrievalTimeout TOMLDuration `toml:"receipt_retrieval_timeout"` ReceiptRetrievalTimeout TOMLDuration `toml:"receipt_retrieval_timeout"`
...@@ -130,12 +128,6 @@ func (c *Config) Validate() error { ...@@ -130,12 +128,6 @@ func (c *Config) Validate() error {
if wallet.TxValue.BitLen() == 0 { if wallet.TxValue.BitLen() == 0 {
return errors.Errorf("wallet [%s] tx_value is missing", name) return errors.Errorf("wallet [%s] tx_value is missing", name)
} }
if wallet.GasLimit == 0 {
return errors.Errorf("wallet [%s] gas_limit is missing", name)
}
if wallet.GasFeeCap.BitLen() == 0 {
return errors.Errorf("wallet [%s] gas_fee_cap is missing", name)
}
} }
for name, provider := range c.Providers { for name, provider := range c.Providers {
...@@ -154,6 +146,9 @@ func (c *Config) Validate() error { ...@@ -154,6 +146,9 @@ func (c *Config) Validate() error {
if provider.SendTransactionRetryTimeout == 0 { if provider.SendTransactionRetryTimeout == 0 {
return errors.Errorf("provider [%s] send_transaction_retry_timeout is missing", name) return errors.Errorf("provider [%s] send_transaction_retry_timeout is missing", name)
} }
if provider.SendTransactionCoolDown == 0 {
return errors.Errorf("provider [%s] send_transaction_cool_down is missing", name)
}
if provider.ReceiptRetrievalInterval == 0 { if provider.ReceiptRetrievalInterval == 0 {
return errors.Errorf("provider [%s] receipt_retrieval_interval is missing", name) return errors.Errorf("provider [%s] receipt_retrieval_interval is missing", name)
} }
......
...@@ -2,6 +2,7 @@ package clients ...@@ -2,6 +2,7 @@ package clients
import ( import (
"context" "context"
"math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics" "github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
...@@ -22,7 +23,7 @@ func Dial(providerName string, url string) (*InstrumentedEthClient, error) { ...@@ -22,7 +23,7 @@ func Dial(providerName string, url string) (*InstrumentedEthClient, error) {
start := time.Now() start := time.Now()
c, err := ethclient.Dial(url) c, err := ethclient.Dial(url)
if err != nil { if err != nil {
metrics.RecordError(providerName, "ethclient.Dial") metrics.RecordErrorDetails(providerName, "ethclient.Dial", err)
return nil, err return nil, err
} }
metrics.RecordRPCLatency(providerName, "ethclient", "Dial", time.Since(start)) metrics.RecordRPCLatency(providerName, "ethclient", "Dial", time.Since(start))
...@@ -34,7 +35,7 @@ func (i *InstrumentedEthClient) TransactionByHash(ctx context.Context, hash comm ...@@ -34,7 +35,7 @@ func (i *InstrumentedEthClient) TransactionByHash(ctx context.Context, hash comm
tx, isPending, err := i.c.TransactionByHash(ctx, hash) tx, isPending, err := i.c.TransactionByHash(ctx, hash)
if err != nil { if err != nil {
if !i.ignorableErrors(err) { if !i.ignorableErrors(err) {
metrics.RecordError(i.providerName, "ethclient.TransactionByHash") metrics.RecordErrorDetails(i.providerName, "ethclient.TransactionByHash", err)
} }
return nil, false, err return nil, false, err
} }
...@@ -46,7 +47,7 @@ func (i *InstrumentedEthClient) PendingNonceAt(ctx context.Context, address stri ...@@ -46,7 +47,7 @@ func (i *InstrumentedEthClient) PendingNonceAt(ctx context.Context, address stri
start := time.Now() start := time.Now()
nonce, err := i.c.PendingNonceAt(ctx, common.HexToAddress(address)) nonce, err := i.c.PendingNonceAt(ctx, common.HexToAddress(address))
if err != nil { if err != nil {
metrics.RecordError(i.providerName, "ethclient.PendingNonceAt") metrics.RecordErrorDetails(i.providerName, "ethclient.PendingNonceAt", err)
return 0, err return 0, err
} }
metrics.RecordRPCLatency(i.providerName, "ethclient", "PendingNonceAt", time.Since(start)) metrics.RecordRPCLatency(i.providerName, "ethclient", "PendingNonceAt", time.Since(start))
...@@ -58,7 +59,7 @@ func (i *InstrumentedEthClient) TransactionReceipt(ctx context.Context, txHash c ...@@ -58,7 +59,7 @@ func (i *InstrumentedEthClient) TransactionReceipt(ctx context.Context, txHash c
receipt, err := i.c.TransactionReceipt(ctx, txHash) receipt, err := i.c.TransactionReceipt(ctx, txHash)
if err != nil { if err != nil {
if !i.ignorableErrors(err) { if !i.ignorableErrors(err) {
metrics.RecordError(i.providerName, "ethclient.TransactionReceipt") metrics.RecordErrorDetails(i.providerName, "ethclient.TransactionReceipt", err)
} }
return nil, err return nil, err
} }
...@@ -71,7 +72,7 @@ func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.T ...@@ -71,7 +72,7 @@ func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.T
err := i.c.SendTransaction(ctx, tx) err := i.c.SendTransaction(ctx, tx)
if err != nil { if err != nil {
if !i.ignorableErrors(err) { if !i.ignorableErrors(err) {
metrics.RecordError(i.providerName, "ethclient.SendTransaction") metrics.RecordErrorDetails(i.providerName, "ethclient.SendTransaction", err)
} }
return err return err
} }
...@@ -79,6 +80,39 @@ func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.T ...@@ -79,6 +80,39 @@ func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.T
return err return err
} }
func (i *InstrumentedEthClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
start := time.Now()
gas, err := i.c.EstimateGas(ctx, msg)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.EstimateGas", err)
return 0, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "EstimateGas", time.Since(start))
return gas, err
}
func (i *InstrumentedEthClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
start := time.Now()
gasTipCap, err := i.c.SuggestGasTipCap(ctx)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.SuggestGasTipCap", err)
return nil, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "SuggestGasTipCap", time.Since(start))
return gasTipCap, err
}
func (i *InstrumentedEthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
start := time.Now()
header, err := i.c.HeaderByNumber(ctx, number)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.HeaderByNumber", err)
return nil, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "HeaderByNumber", time.Since(start))
return header, err
}
func (i *InstrumentedEthClient) ignorableErrors(err error) bool { func (i *InstrumentedEthClient) ignorableErrors(err error) bool {
msg := err.Error() msg := err.Error()
// we dont use errors.Is because eth client actually uses errors.New, // we dont use errors.Is because eth client actually uses errors.New,
......
...@@ -22,7 +22,7 @@ func NewSignerClient(providerName string, logger log.Logger, endpoint string, tl ...@@ -22,7 +22,7 @@ func NewSignerClient(providerName string, logger log.Logger, endpoint string, tl
start := time.Now() start := time.Now()
c, err := signer.NewSignerClient(logger, endpoint, tlsConfig) c, err := signer.NewSignerClient(logger, endpoint, tlsConfig)
if err != nil { if err != nil {
metrics.RecordError(providerName, "signer.NewSignerClient") metrics.RecordErrorDetails(providerName, "signer.NewSignerClient", err)
return nil, err return nil, err
} }
metrics.RecordRPCLatency(providerName, "signer", "NewSignerClient", time.Since(start)) metrics.RecordRPCLatency(providerName, "signer", "NewSignerClient", time.Since(start))
...@@ -33,7 +33,7 @@ func (i *InstrumentedSignerClient) SignTransaction(ctx context.Context, chainId ...@@ -33,7 +33,7 @@ func (i *InstrumentedSignerClient) SignTransaction(ctx context.Context, chainId
start := time.Now() start := time.Now()
tx, err := i.c.SignTransaction(ctx, chainId, tx) tx, err := i.c.SignTransaction(ctx, chainId, tx)
if err != nil { if err != nil {
metrics.RecordError(i.providerName, "signer.SignTransaction") metrics.RecordErrorDetails(i.providerName, "signer.SignTransaction", err)
return nil, err return nil, err
} }
metrics.RecordRPCLatency(i.providerName, "signer", "SignTransaction", time.Since(start)) metrics.RecordRPCLatency(i.providerName, "signer", "SignTransaction", time.Since(start))
......
...@@ -2,6 +2,7 @@ package provider ...@@ -2,6 +2,7 @@ package provider
import ( import (
"context" "context"
"math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics" "github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
...@@ -21,7 +22,7 @@ import ( ...@@ -21,7 +22,7 @@ import (
// RoundTrip send a new transaction to measure round trip latency // RoundTrip send a new transaction to measure round trip latency
func (p *Provider) RoundTrip(ctx context.Context) { func (p *Provider) RoundTrip(ctx context.Context) {
log.Debug("roundTripLatency", log.Debug("RoundTrip",
"provider", p.name) "provider", p.name)
client, err := iclients.Dial(p.name, p.config.URL) client, err := iclients.Dial(p.name, p.config.URL)
...@@ -33,33 +34,38 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -33,33 +34,38 @@ func (p *Provider) RoundTrip(ctx context.Context) {
return return
} }
var nonce uint64 p.txPool.ExclusiveSend.Lock()
p.txPool.M.Lock() defer p.txPool.ExclusiveSend.Unlock()
if p.txPool.Nonce == uint64(0) {
nonce, err = client.PendingNonceAt(ctx, p.walletConfig.Address)
if err != nil {
log.Error("cant get nounce",
"provider", p.name,
"err", err)
p.txPool.M.Unlock()
return
}
p.txPool.Nonce = nonce
} else {
p.txPool.Nonce++
nonce = p.txPool.Nonce
}
p.txPool.M.Unlock()
txHash := common.Hash{} txHash := common.Hash{}
attempt := 0 attempt := 0
nonce := uint64(0)
// used for timeout // used for timeout
firstAttemptAt := time.Now() firstAttemptAt := time.Now()
// used for actual round trip time (disregard retry time) // used for actual round trip time (disregard retry time)
roundTripStartedAt := time.Now() var roundTripStartedAt time.Time
for { for {
tx := p.createTx(nonce)
txHash = tx.Hash() // sleep until we get a clear to send
for {
coolDown := time.Duration(p.config.SendTransactionCoolDown) - time.Since(p.txPool.LastSend)
if coolDown > 0 {
time.Sleep(coolDown)
} else {
break
}
}
tx, err := p.createTx(ctx, client, nonce)
nonce = tx.Nonce()
if err != nil {
log.Error("cant create tx",
"provider", p.name,
"nonce", nonce,
"err", err)
return
}
signedTx, err := p.sign(ctx, tx) signedTx, err := p.sign(ctx, tx)
if err != nil { if err != nil {
...@@ -69,7 +75,6 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -69,7 +75,6 @@ func (p *Provider) RoundTrip(ctx context.Context) {
"err", err) "err", err)
return return
} }
txHash = signedTx.Hash() txHash = signedTx.Hash()
roundTripStartedAt = time.Now() roundTripStartedAt = time.Now()
...@@ -78,25 +83,29 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -78,25 +83,29 @@ func (p *Provider) RoundTrip(ctx context.Context) {
if err.Error() == txpool.ErrAlreadyKnown.Error() || if err.Error() == txpool.ErrAlreadyKnown.Error() ||
err.Error() == txpool.ErrReplaceUnderpriced.Error() || err.Error() == txpool.ErrReplaceUnderpriced.Error() ||
err.Error() == core.ErrNonceTooLow.Error() { err.Error() == core.ErrNonceTooLow.Error() {
log.Warn("cant send transaction (retryable)",
"provider", p.name,
"err", err,
"nonce", nonce)
if time.Since(firstAttemptAt) >= time.Duration(p.config.SendTransactionRetryTimeout) { if time.Since(firstAttemptAt) >= time.Duration(p.config.SendTransactionRetryTimeout) {
log.Error("send transaction timed out (known already)", log.Error("send transaction timed out (known already)",
"provider", p.name, "provider", p.name,
"hash", txHash.Hex(), "hash", txHash.Hex(),
"nonce", nonce,
"elapsed", time.Since(firstAttemptAt), "elapsed", time.Since(firstAttemptAt),
"attempt", attempt, "attempt", attempt)
"nonce", nonce) metrics.RecordErrorDetails(p.name, "send.timeout", err)
metrics.RecordError(p.name, "ethclient.SendTransaction.nonce")
return return
} }
log.Warn("tx already known, incrementing nonce and trying again", log.Warn("tx already known, incrementing nonce and trying again",
"provider", p.name, "provider", p.name,
"nonce", nonce) "nonce", nonce)
time.Sleep(time.Duration(p.config.SendTransactionRetryInterval)) time.Sleep(time.Duration(p.config.SendTransactionRetryInterval))
p.txPool.M.Lock() nonce++
p.txPool.Nonce++
nonce = p.txPool.Nonce
p.txPool.M.Unlock()
attempt++ attempt++
if attempt%10 == 0 { if attempt%10 == 0 {
log.Debug("retrying send transaction...", log.Debug("retrying send transaction...",
...@@ -108,6 +117,7 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -108,6 +117,7 @@ func (p *Provider) RoundTrip(ctx context.Context) {
} else { } else {
log.Error("cant send transaction", log.Error("cant send transaction",
"provider", p.name, "provider", p.name,
"nonce", nonce,
"err", err) "err", err)
metrics.RecordErrorDetails(p.name, "ethclient.SendTransaction", err) metrics.RecordErrorDetails(p.name, "ethclient.SendTransaction", err)
return return
...@@ -131,6 +141,7 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -131,6 +141,7 @@ func (p *Provider) RoundTrip(ctx context.Context) {
SentAt: sentAt, SentAt: sentAt,
SeenBy: make(map[string]time.Time), SeenBy: make(map[string]time.Time),
} }
p.txPool.LastSend = sentAt
p.txPool.M.Unlock() p.txPool.M.Unlock()
var receipt *types.Receipt var receipt *types.Receipt
...@@ -140,13 +151,17 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -140,13 +151,17 @@ func (p *Provider) RoundTrip(ctx context.Context) {
log.Error("receipt retrieval timed out", log.Error("receipt retrieval timed out",
"provider", p.name, "provider", p.name,
"hash", txHash, "hash", txHash,
"nonce", nonce,
"elapsed", time.Since(sentAt)) "elapsed", time.Since(sentAt))
metrics.RecordErrorDetails(p.name, "receipt.timeout", err)
return return
} }
time.Sleep(time.Duration(p.config.ReceiptRetrievalInterval)) time.Sleep(time.Duration(p.config.ReceiptRetrievalInterval))
if attempt%10 == 0 { if attempt%10 == 0 {
log.Debug("checking for receipt...", log.Debug("checking for receipt...",
"provider", p.name, "provider", p.name,
"hash", txHash,
"nonce", nonce,
"attempt", attempt, "attempt", attempt,
"elapsed", time.Since(sentAt)) "elapsed", time.Since(sentAt))
} }
...@@ -155,6 +170,7 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -155,6 +170,7 @@ func (p *Provider) RoundTrip(ctx context.Context) {
log.Error("cant get receipt for transaction", log.Error("cant get receipt for transaction",
"provider", p.name, "provider", p.name,
"hash", txHash.Hex(), "hash", txHash.Hex(),
"nonce", nonce,
"err", err) "err", err)
return return
} }
...@@ -168,6 +184,7 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -168,6 +184,7 @@ func (p *Provider) RoundTrip(ctx context.Context) {
log.Info("got transaction receipt", log.Info("got transaction receipt",
"hash", txHash.Hex(), "hash", txHash.Hex(),
"nonce", nonce,
"roundTripLatency", roundTripLatency, "roundTripLatency", roundTripLatency,
"provider", p.name, "provider", p.name,
"blockNumber", receipt.BlockNumber, "blockNumber", receipt.BlockNumber,
...@@ -175,20 +192,83 @@ func (p *Provider) RoundTrip(ctx context.Context) { ...@@ -175,20 +192,83 @@ func (p *Provider) RoundTrip(ctx context.Context) {
"gasUsed", receipt.GasUsed) "gasUsed", receipt.GasUsed)
} }
func (p *Provider) createTx(nonce uint64) *types.Transaction { func (p *Provider) createTx(ctx context.Context, client *iclients.InstrumentedEthClient, nonce uint64) (*types.Transaction, error) {
toAddress := common.HexToAddress(p.walletConfig.Address) var err error
if nonce == 0 {
nonce, err = client.PendingNonceAt(ctx, p.walletConfig.Address)
if err != nil {
log.Error("cant get nounce",
"provider", p.name,
"nonce", nonce,
"err", err)
return nil, err
}
}
gasTipCap, err := client.SuggestGasTipCap(ctx)
if err != nil {
log.Error("cant get gas tip cap",
"provider", p.name,
"err", err)
return nil, err
}
gasTipCap = new(big.Int).Mul(gasTipCap, big.NewInt(110))
gasTipCap = new(big.Int).Div(gasTipCap, big.NewInt(100))
head, err := client.HeaderByNumber(ctx, nil)
if err != nil {
log.Error("cant get base fee from head",
"provider", p.name,
"err", err)
return nil, err
}
baseFee := head.BaseFee
gasFeeCap := new(big.Int).Add(
gasTipCap,
new(big.Int).Mul(baseFee, big.NewInt(2)))
addr := common.HexToAddress(p.walletConfig.Address)
var data []byte var data []byte
tx := types.NewTx(&types.DynamicFeeTx{ dynamicTx := &types.DynamicFeeTx{
ChainID: &p.walletConfig.ChainID, ChainID: &p.walletConfig.ChainID,
Nonce: nonce, Nonce: nonce,
GasFeeCap: &p.walletConfig.GasFeeCap, GasFeeCap: gasFeeCap,
GasTipCap: &p.walletConfig.GasTipCap, GasTipCap: gasTipCap,
Gas: p.walletConfig.GasLimit, To: &addr,
To: &toAddress,
Value: &p.walletConfig.TxValue, Value: &p.walletConfig.TxValue,
Data: data, Data: data,
}
gas, err := client.EstimateGas(ctx, ethereum.CallMsg{
From: addr,
To: &addr,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Data: dynamicTx.Data,
Value: dynamicTx.Value,
}) })
return tx if err != nil {
log.Error("cant estimate gas",
"provider", p.name,
"err", err)
return nil, err
}
dynamicTx.Gas = gas
tx := types.NewTx(dynamicTx)
log.Info("tx created",
"provider", p.name,
"from", addr,
"to", dynamicTx.To,
"nonce", dynamicTx.Nonce,
"value", dynamicTx.Value,
"gas", dynamicTx.Gas,
"gasTipCap", dynamicTx.GasTipCap,
"gasFeeCap", dynamicTx.GasFeeCap,
)
return tx, nil
} }
func (p *Provider) sign(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { func (p *Provider) sign(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) {
......
...@@ -15,7 +15,11 @@ type NetworkTransactionPool struct { ...@@ -15,7 +15,11 @@ type NetworkTransactionPool struct {
M sync.Mutex M sync.Mutex
Transactions map[string]*TransactionState Transactions map[string]*TransactionState
Expected int Expected int
Nonce uint64
// Last time a transaction was sent
LastSend time.Time
// Prevents concurrent transaction send
ExclusiveSend sync.Mutex
} }
type TransactionState struct { type TransactionState struct {
......
...@@ -26,3 +26,6 @@ deployments/hardhat ...@@ -26,3 +26,6 @@ deployments/hardhat
deployments/getting-started deployments/getting-started
deployments/*/.deploy deployments/*/.deploy
deployments/1337 deployments/1337
# Devnet config which changes with each 'make devnet-up'
deploy-config/devnetL1.json
...@@ -23,7 +23,7 @@ importers: ...@@ -23,7 +23,7 @@ importers:
version: 0.4.8 version: 0.4.8
'@nrwl/nx-cloud': '@nrwl/nx-cloud':
specifier: latest specifier: latest
version: 16.3.0 version: 16.4.0
'@types/chai': '@types/chai':
specifier: ^4.2.18 specifier: ^4.2.18
version: 4.2.21 version: 4.2.21
...@@ -2534,6 +2534,10 @@ packages: ...@@ -2534,6 +2534,10 @@ packages:
resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==} resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
/@noble/hashes@1.3.2:
resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
engines: {node: '>= 16'}
/@nodelib/fs.scandir@2.1.5: /@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
...@@ -2669,10 +2673,10 @@ packages: ...@@ -2669,10 +2673,10 @@ packages:
- nx - nx
dev: true dev: true
/@nrwl/nx-cloud@16.3.0: /@nrwl/nx-cloud@16.4.0:
resolution: {integrity: sha512-nJrGsVufhY74KcP7kM7BqFOGAoO5OEF6+wfiM295DgmEG9c1yW+x5QiQaC42K9SWYn/eKQa1X7466ZA5lynXoQ==} resolution: {integrity: sha512-QitrYK6z9ceagetBlgLMZnC0T85k2JTk+oK0MxZ5p/woclqeYN7SiGNZgMzDq8TjJwt8Fm/MDnsSo3xtufmLBg==}
dependencies: dependencies:
nx-cloud: 16.3.0 nx-cloud: 16.4.0
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
dev: true dev: true
...@@ -3071,7 +3075,7 @@ packages: ...@@ -3071,7 +3075,7 @@ packages:
/@scure/bip39@1.2.1: /@scure/bip39@1.2.1:
resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==}
dependencies: dependencies:
'@noble/hashes': 1.3.1 '@noble/hashes': 1.3.2
'@scure/base': 1.1.1 '@scure/base': 1.1.1
/@sentry-internal/tracing@7.64.0: /@sentry-internal/tracing@7.64.0:
...@@ -3713,20 +3717,20 @@ packages: ...@@ -3713,20 +3717,20 @@ packages:
/@types/bn.js@4.11.6: /@types/bn.js@4.11.6:
resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/bn.js@5.1.0: /@types/bn.js@5.1.0:
resolution: {integrity: sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==} resolution: {integrity: sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/body-parser@1.19.1: /@types/body-parser@1.19.1:
resolution: {integrity: sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==} resolution: {integrity: sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==}
dependencies: dependencies:
'@types/connect': 3.4.35 '@types/connect': 3.4.35
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/chai-as-promised@7.1.5: /@types/chai-as-promised@7.1.5:
...@@ -3752,7 +3756,7 @@ packages: ...@@ -3752,7 +3756,7 @@ packages:
/@types/connect@3.4.35: /@types/connect@3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
/@types/dateformat@5.0.0: /@types/dateformat@5.0.0:
resolution: {integrity: sha512-SZg4JdHIWHQGEokbYGZSDvo5wA4TLYPXaqhigs/wH+REDOejcJzgH+qyY+HtEUtWOZxEUkbhbdYPqQDiEgrXeA==} resolution: {integrity: sha512-SZg4JdHIWHQGEokbYGZSDvo5wA4TLYPXaqhigs/wH+REDOejcJzgH+qyY+HtEUtWOZxEUkbhbdYPqQDiEgrXeA==}
...@@ -3766,7 +3770,7 @@ packages: ...@@ -3766,7 +3770,7 @@ packages:
/@types/express-serve-static-core@4.17.35: /@types/express-serve-static-core@4.17.35:
resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
'@types/qs': 6.9.7 '@types/qs': 6.9.7
'@types/range-parser': 1.2.4 '@types/range-parser': 1.2.4
'@types/send': 0.17.1 '@types/send': 0.17.1
...@@ -3812,7 +3816,7 @@ packages: ...@@ -3812,7 +3816,7 @@ packages:
dependencies: dependencies:
'@types/abstract-leveldown': 5.0.2 '@types/abstract-leveldown': 5.0.2
'@types/level-errors': 3.0.0 '@types/level-errors': 3.0.0
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/lru-cache@5.1.1: /@types/lru-cache@5.1.1:
...@@ -3843,7 +3847,7 @@ packages: ...@@ -3843,7 +3847,7 @@ packages:
/@types/mkdirp@0.5.2: /@types/mkdirp@0.5.2:
resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/mocha@10.0.1: /@types/mocha@10.0.1:
...@@ -3862,7 +3866,7 @@ packages: ...@@ -3862,7 +3866,7 @@ packages:
/@types/node-fetch@2.6.4: /@types/node-fetch@2.6.4:
resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==} resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
form-data: 3.0.1 form-data: 3.0.1
dev: true dev: true
...@@ -3875,10 +3879,10 @@ packages: ...@@ -3875,10 +3879,10 @@ packages:
/@types/node@20.5.0: /@types/node@20.5.0:
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==} resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
dev: true
/@types/node@20.5.3: /@types/node@20.5.3:
resolution: {integrity: sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==} resolution: {integrity: sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==}
dev: true
/@types/normalize-package-data@2.4.1: /@types/normalize-package-data@2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
...@@ -3890,7 +3894,7 @@ packages: ...@@ -3890,7 +3894,7 @@ packages:
/@types/pbkdf2@3.1.0: /@types/pbkdf2@3.1.0:
resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/pino-multi-stream@5.1.3: /@types/pino-multi-stream@5.1.3:
...@@ -3908,13 +3912,13 @@ packages: ...@@ -3908,13 +3912,13 @@ packages:
/@types/pino-std-serializers@2.4.1: /@types/pino-std-serializers@2.4.1:
resolution: {integrity: sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ==} resolution: {integrity: sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/pino@6.3.11: /@types/pino@6.3.11:
resolution: {integrity: sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ==} resolution: {integrity: sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
'@types/pino-pretty': 4.7.1 '@types/pino-pretty': 4.7.1
'@types/pino-std-serializers': 2.4.1 '@types/pino-std-serializers': 2.4.1
sonic-boom: 2.8.0 sonic-boom: 2.8.0
...@@ -3964,7 +3968,7 @@ packages: ...@@ -3964,7 +3968,7 @@ packages:
/@types/secp256k1@4.0.3: /@types/secp256k1@4.0.3:
resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/seedrandom@3.0.1: /@types/seedrandom@3.0.1:
...@@ -3983,14 +3987,14 @@ packages: ...@@ -3983,14 +3987,14 @@ packages:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies: dependencies:
'@types/mime': 1.3.2 '@types/mime': 1.3.2
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/serve-static@1.13.10: /@types/serve-static@1.13.10:
resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==} resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
dependencies: dependencies:
'@types/mime': 1.3.2 '@types/mime': 1.3.2
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@types/sinon-chai@3.2.5: /@types/sinon-chai@3.2.5:
...@@ -4027,18 +4031,18 @@ packages: ...@@ -4027,18 +4031,18 @@ packages:
/@types/ws@7.4.7: /@types/ws@7.4.7:
resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
/@types/ws@8.5.3: /@types/ws@8.5.3:
resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: false dev: false
/@types/ws@8.5.5: /@types/ws@8.5.5:
resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==}
dependencies: dependencies:
'@types/node': 20.5.0 '@types/node': 20.5.3
dev: true dev: true
/@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.60.1)(eslint@8.47.0)(typescript@5.1.6): /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.60.1)(eslint@8.47.0)(typescript@5.1.6):
...@@ -12293,11 +12297,11 @@ packages: ...@@ -12293,11 +12297,11 @@ packages:
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
dev: true dev: true
/nx-cloud@16.3.0: /nx-cloud@16.4.0:
resolution: {integrity: sha512-hmNgpeLO4v4WDSWa8YhwX+q+9ohIyY8iqxlWyIKixWzQH2XfRgYFjOLH4IDLGOlKa3hg7MB6+4+75cK9CfSmKw==} resolution: {integrity: sha512-jbq4hWvDwRlJVpxgMgbmNSkue+6XZSn53R6Vo6qmCAWODJ9KY1BZdZ/9VRL8IX/BRKebVFiXp3SapFB1qPhH8A==}
hasBin: true hasBin: true
dependencies: dependencies:
'@nrwl/nx-cloud': 16.3.0 '@nrwl/nx-cloud': 16.4.0
axios: 1.1.3 axios: 1.1.3
chalk: 4.1.2 chalk: 4.1.2
dotenv: 10.0.0 dotenv: 10.0.0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment