Add missing fields to RPC object conversion (#2863)
* Add missing fields to RPC object conversion * Fix populateBlockObject call * Remove server_api_helpers.nim * Add metric defined conditional compilation * link with rocksdb
This commit is contained in:
parent
a241050c94
commit
7b2b59a976
6
Makefile
6
Makefile
|
@ -322,17 +322,17 @@ utp-test: | build deps
|
|||
# Nimbus Verified Proxy related targets
|
||||
|
||||
# Builds the nimbus_verified_proxy
|
||||
nimbus_verified_proxy: | build deps
|
||||
nimbus_verified_proxy: | build deps rocksdb
|
||||
echo -e $(BUILD_MSG) "build/$@" && \
|
||||
$(ENV_SCRIPT) nim nimbus_verified_proxy $(NIM_PARAMS) nimbus.nims
|
||||
|
||||
# builds and runs the nimbus_verified_proxy test suite
|
||||
nimbus-verified-proxy-test: | build deps
|
||||
nimbus-verified-proxy-test: | build deps rocksdb
|
||||
$(ENV_SCRIPT) nim nimbus_verified_proxy_test $(NIM_PARAMS) nimbus.nims
|
||||
|
||||
# Shared library for verified proxy
|
||||
|
||||
libverifproxy: | build deps
|
||||
libverifproxy: | build deps rocksdb
|
||||
+ echo -e $(BUILD_MSG) "build/$@" && \
|
||||
$(ENV_SCRIPT) nim --version && \
|
||||
$(ENV_SCRIPT) nim c --app:lib -d:"libp2p_pki_schemes=secp256k1" --noMain:on --threads:on --nimcache:nimcache/libverifproxy -o:$(VERIF_PROXY_OUT_PATH)/$@.$(VERIF_PROXY_SHAREDLIBEXT) $(NIM_PARAMS) nimbus_verified_proxy/libverifproxy/verifproxy.nim
|
||||
|
|
|
@ -20,7 +20,6 @@ import
|
|||
../../[aristo_blobify, aristo_desc],
|
||||
../init_common,
|
||||
./rdb_desc,
|
||||
metrics,
|
||||
std/concurrency/atomics
|
||||
|
||||
const
|
||||
|
@ -34,49 +33,53 @@ when extraTraceMessages:
|
|||
logScope:
|
||||
topics = "aristo-rocksdb"
|
||||
|
||||
type
|
||||
RdbVtxLruCounter = ref object of Counter
|
||||
RdbKeyLruCounter = ref object of Counter
|
||||
|
||||
var
|
||||
rdbVtxLruStatsMetric {.used.} = RdbVtxLruCounter.newCollector(
|
||||
"aristo_rdb_vtx_lru_total",
|
||||
"Vertex LRU lookup (hit/miss, world/account, branch/leaf)",
|
||||
labels = ["state", "vtype", "hit"],
|
||||
)
|
||||
rdbKeyLruStatsMetric {.used.} = RdbKeyLruCounter.newCollector(
|
||||
"aristo_rdb_key_lru_total", "HashKey LRU lookup", labels = ["state", "hit"]
|
||||
)
|
||||
|
||||
method collect*(collector: RdbVtxLruCounter, output: MetricHandler) =
|
||||
let timestamp = collector.now()
|
||||
|
||||
# We don't care about synchronization between each type of metric or between
|
||||
# the metrics thread and others since small differences like this don't matter
|
||||
for state in RdbStateType:
|
||||
for vtype in VertexType:
|
||||
when defined(metrics):
|
||||
import
|
||||
metrics
|
||||
|
||||
type
|
||||
RdbVtxLruCounter = ref object of Counter
|
||||
RdbKeyLruCounter = ref object of Counter
|
||||
|
||||
var
|
||||
rdbVtxLruStatsMetric {.used.} = RdbVtxLruCounter.newCollector(
|
||||
"aristo_rdb_vtx_lru_total",
|
||||
"Vertex LRU lookup (hit/miss, world/account, branch/leaf)",
|
||||
labels = ["state", "vtype", "hit"],
|
||||
)
|
||||
rdbKeyLruStatsMetric {.used.} = RdbKeyLruCounter.newCollector(
|
||||
"aristo_rdb_key_lru_total", "HashKey LRU lookup", labels = ["state", "hit"]
|
||||
)
|
||||
|
||||
method collect*(collector: RdbVtxLruCounter, output: MetricHandler) =
|
||||
let timestamp = collector.now()
|
||||
|
||||
# We don't care about synchronization between each type of metric or between
|
||||
# the metrics thread and others since small differences like this don't matter
|
||||
for state in RdbStateType:
|
||||
for vtype in VertexType:
|
||||
for hit in [false, true]:
|
||||
output(
|
||||
name = "aristo_rdb_vtx_lru_total",
|
||||
value = float64(rdbVtxLruStats[state][vtype].get(hit)),
|
||||
labels = ["state", "vtype", "hit"],
|
||||
labelValues = [$state, $vtype, $ord(hit)],
|
||||
timestamp = timestamp,
|
||||
)
|
||||
|
||||
method collect*(collector: RdbKeyLruCounter, output: MetricHandler) =
|
||||
let timestamp = collector.now()
|
||||
|
||||
for state in RdbStateType:
|
||||
for hit in [false, true]:
|
||||
output(
|
||||
name = "aristo_rdb_vtx_lru_total",
|
||||
value = float64(rdbVtxLruStats[state][vtype].get(hit)),
|
||||
labels = ["state", "vtype", "hit"],
|
||||
labelValues = [$state, $vtype, $ord(hit)],
|
||||
name = "aristo_rdb_key_lru_total",
|
||||
value = float64(rdbKeyLruStats[state].get(hit)),
|
||||
labels = ["state", "hit"],
|
||||
labelValues = [$state, $ord(hit)],
|
||||
timestamp = timestamp,
|
||||
)
|
||||
|
||||
method collect*(collector: RdbKeyLruCounter, output: MetricHandler) =
|
||||
let timestamp = collector.now()
|
||||
|
||||
for state in RdbStateType:
|
||||
for hit in [false, true]:
|
||||
output(
|
||||
name = "aristo_rdb_key_lru_total",
|
||||
value = float64(rdbKeyLruStats[state].get(hit)),
|
||||
labels = ["state", "hit"],
|
||||
labelValues = [$state, $ord(hit)],
|
||||
timestamp = timestamp,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -54,7 +54,7 @@ proc calculateMedianGasPrice*(chain: CoreDbRef): GasInt {.raises: [RlpError].} =
|
|||
# For compatibility with `ethpandaops/ethereum-package`, set this to a
|
||||
# sane minimum for compatibility to unblock testing.
|
||||
# Note: When this is fixed, update `tests/graphql/queries.toml` and
|
||||
# re-enable the "query.gasPrice" test case (remove `skip = true`).
|
||||
# re-enable the "query.gasPrice" test case (remove `skip = true`).
|
||||
result = max(result, minGasPrice)
|
||||
|
||||
proc unsignedTx*(tx: TransactionArgs, chain: CoreDbRef, defaultNonce: AccountNonce, chainId: ChainId): Transaction
|
||||
|
@ -92,112 +92,126 @@ proc unsignedTx*(tx: TransactionArgs, chain: CoreDbRef, defaultNonce: AccountNon
|
|||
|
||||
proc toWd(wd: Withdrawal): WithdrawalObject =
|
||||
WithdrawalObject(
|
||||
index: Quantity wd.index,
|
||||
index: Quantity(wd.index),
|
||||
validatorIndex: Quantity wd.validatorIndex,
|
||||
address: wd.address,
|
||||
amount: Quantity wd.amount,
|
||||
)
|
||||
|
||||
proc toWdList(list: openArray[Withdrawal]): seq[WithdrawalObject] =
|
||||
var res = newSeqOfCap[WithdrawalObject](list.len)
|
||||
result = newSeqOfCap[WithdrawalObject](list.len)
|
||||
for x in list:
|
||||
res.add toWd(x)
|
||||
return res
|
||||
result.add toWd(x)
|
||||
|
||||
func toWdList(x: Opt[seq[eth_types.Withdrawal]]):
|
||||
func toWdList(x: Opt[seq[Withdrawal]]):
|
||||
Opt[seq[WithdrawalObject]] =
|
||||
if x.isNone: Opt.none(seq[WithdrawalObject])
|
||||
else: Opt.some(toWdList x.get)
|
||||
|
||||
func toAuth*(x: Authorization): AuthorizationObject =
|
||||
AuthorizationObject(
|
||||
chainId: Quantity(x.chainId),
|
||||
address: x.address,
|
||||
nonce: Quantity(x.nonce),
|
||||
v: Quantity(x.v),
|
||||
r: x.r,
|
||||
s: x.s,
|
||||
)
|
||||
|
||||
proc toAuthList(list: openArray[Authorization]): seq[AuthorizationObject] =
|
||||
result = newSeqOfCap[AuthorizationObject](list.len)
|
||||
for x in list:
|
||||
result.add toAuth(x)
|
||||
|
||||
proc populateTransactionObject*(tx: Transaction,
|
||||
optionalHash: Opt[eth_types.Hash32] = Opt.none(eth_types.Hash32),
|
||||
optionalNumber: Opt[eth_types.BlockNumber] = Opt.none(eth_types.BlockNumber),
|
||||
txIndex: Opt[uint64] = Opt.none(uint64)): TransactionObject =
|
||||
var res = TransactionObject()
|
||||
res.`type` = Opt.some Quantity(tx.txType)
|
||||
res.blockHash = optionalHash
|
||||
res.blockNumber = w3Qty(optionalNumber)
|
||||
result = TransactionObject()
|
||||
result.`type` = Opt.some Quantity(tx.txType)
|
||||
result.blockHash = optionalHash
|
||||
result.blockNumber = w3Qty(optionalNumber)
|
||||
|
||||
if (let sender = tx.recoverSender(); sender.isOk):
|
||||
res.`from` = sender[]
|
||||
res.gas = Quantity(tx.gasLimit)
|
||||
res.gasPrice = Quantity(tx.gasPrice)
|
||||
res.hash = tx.rlpHash
|
||||
res.input = tx.payload
|
||||
res.nonce = Quantity(tx.nonce)
|
||||
res.to = Opt.some(tx.destination)
|
||||
result.`from` = sender[]
|
||||
result.gas = Quantity(tx.gasLimit)
|
||||
result.gasPrice = Quantity(tx.gasPrice)
|
||||
result.hash = tx.rlpHash
|
||||
result.input = tx.payload
|
||||
result.nonce = Quantity(tx.nonce)
|
||||
result.to = Opt.some(tx.destination)
|
||||
if txIndex.isSome:
|
||||
res.transactionIndex = Opt.some(Quantity(txIndex.get))
|
||||
res.value = tx.value
|
||||
res.v = Quantity(tx.V)
|
||||
res.r = tx.R
|
||||
res.s = tx.S
|
||||
res.maxFeePerGas = Opt.some Quantity(tx.maxFeePerGas)
|
||||
res.maxPriorityFeePerGas = Opt.some Quantity(tx.maxPriorityFeePerGas)
|
||||
result.transactionIndex = Opt.some(Quantity(txIndex.get))
|
||||
result.value = tx.value
|
||||
result.v = Quantity(tx.V)
|
||||
result.r = tx.R
|
||||
result.s = tx.S
|
||||
result.maxFeePerGas = Opt.some Quantity(tx.maxFeePerGas)
|
||||
result.maxPriorityFeePerGas = Opt.some Quantity(tx.maxPriorityFeePerGas)
|
||||
|
||||
if tx.txType >= TxEip2930:
|
||||
res.chainId = Opt.some(Quantity(tx.chainId))
|
||||
res.accessList = Opt.some(tx.accessList)
|
||||
result.chainId = Opt.some(Quantity(tx.chainId))
|
||||
result.accessList = Opt.some(tx.accessList)
|
||||
|
||||
if tx.txType >= TxEip4844:
|
||||
res.maxFeePerBlobGas = Opt.some(tx.maxFeePerBlobGas)
|
||||
res.blobVersionedHashes = Opt.some(tx.versionedHashes)
|
||||
result.maxFeePerBlobGas = Opt.some(tx.maxFeePerBlobGas)
|
||||
result.blobVersionedHashes = Opt.some(tx.versionedHashes)
|
||||
|
||||
return res
|
||||
if tx.txType >= TxEip7702:
|
||||
result.authorizationList = Opt.some(toAuthList(tx.authorizationList))
|
||||
|
||||
proc populateBlockObject*(blockHash: Hash32,
|
||||
proc populateBlockObject*(blockHash: eth_types.Hash32,
|
||||
blk: Block,
|
||||
totalDifficulty: UInt256,
|
||||
fullTx: bool,
|
||||
isUncle = false): BlockObject =
|
||||
withUncles: bool = false): BlockObject =
|
||||
template header: auto = blk.header
|
||||
|
||||
var res = BlockObject()
|
||||
res.number = Quantity(header.number)
|
||||
res.hash = blockHash
|
||||
res.parentHash = header.parentHash
|
||||
res.nonce = Opt.some(header.nonce)
|
||||
res.sha3Uncles = header.ommersHash
|
||||
res.logsBloom = header.logsBloom
|
||||
res.transactionsRoot = header.txRoot
|
||||
res.stateRoot = header.stateRoot
|
||||
res.receiptsRoot = header.receiptsRoot
|
||||
res.miner = header.coinbase
|
||||
res.difficulty = header.difficulty
|
||||
res.extraData = HistoricExtraData header.extraData
|
||||
res.mixHash = Hash32 header.mixHash
|
||||
result = BlockObject()
|
||||
result.number = Quantity(header.number)
|
||||
result.hash = blockHash
|
||||
result.parentHash = header.parentHash
|
||||
result.nonce = Opt.some(header.nonce)
|
||||
result.sha3Uncles = header.ommersHash
|
||||
result.logsBloom = header.logsBloom
|
||||
result.transactionsRoot = header.txRoot
|
||||
result.stateRoot = header.stateRoot
|
||||
result.receiptsRoot = header.receiptsRoot
|
||||
result.miner = header.coinbase
|
||||
result.difficulty = header.difficulty
|
||||
result.extraData = HistoricExtraData header.extraData
|
||||
result.mixHash = Hash32 header.mixHash
|
||||
|
||||
# discard sizeof(seq[byte]) of extraData and use actual length
|
||||
let size = sizeof(Header) - sizeof(seq[byte]) + header.extraData.len
|
||||
res.size = Quantity(size)
|
||||
let size = sizeof(eth_types.Header) - sizeof(eth_api_types.Blob) + header.extraData.len
|
||||
result.size = Quantity(size)
|
||||
|
||||
res.gasLimit = Quantity(header.gasLimit)
|
||||
res.gasUsed = Quantity(header.gasUsed)
|
||||
res.timestamp = Quantity(header.timestamp)
|
||||
res.baseFeePerGas = header.baseFeePerGas
|
||||
res.totalDifficulty = totalDifficulty
|
||||
result.gasLimit = Quantity(header.gasLimit)
|
||||
result.gasUsed = Quantity(header.gasUsed)
|
||||
result.timestamp = Quantity(header.timestamp)
|
||||
result.baseFeePerGas = header.baseFeePerGas
|
||||
result.totalDifficulty = totalDifficulty
|
||||
|
||||
if not isUncle:
|
||||
res.uncles = blk.uncles.mapIt(it.blockHash)
|
||||
if not withUncles:
|
||||
result.uncles = blk.uncles.mapIt(it.blockHash)
|
||||
|
||||
if fullTx:
|
||||
for i, tx in blk.transactions:
|
||||
let txObj = populateTransactionObject(tx,
|
||||
Opt.some(blockHash),
|
||||
Opt.some(header.number), Opt.some(i.uint64))
|
||||
res.transactions.add txOrHash(txObj)
|
||||
else:
|
||||
for i, tx in blk.transactions:
|
||||
let txHash = rlpHash(tx)
|
||||
res.transactions.add txOrHash(txHash)
|
||||
if fullTx:
|
||||
for i, tx in blk.transactions:
|
||||
let txObj = populateTransactionObject(tx,
|
||||
Opt.some(blockHash),
|
||||
Opt.some(header.number), Opt.some(i.uint64))
|
||||
result.transactions.add txOrHash(txObj)
|
||||
else:
|
||||
for i, tx in blk.transactions:
|
||||
let txHash = rlpHash(tx)
|
||||
result.transactions.add txOrHash(txHash)
|
||||
|
||||
res.withdrawalsRoot = header.withdrawalsRoot
|
||||
res.withdrawals = toWdList blk.withdrawals
|
||||
res.parentBeaconBlockRoot = header.parentBeaconBlockRoot
|
||||
res.blobGasUsed = w3Qty(header.blobGasUsed)
|
||||
res.excessBlobGas = w3Qty(header.excessBlobGas)
|
||||
|
||||
return res
|
||||
result.withdrawalsRoot = header.withdrawalsRoot
|
||||
result.withdrawals = toWdList blk.withdrawals
|
||||
result.parentBeaconBlockRoot = header.parentBeaconBlockRoot
|
||||
result.blobGasUsed = w3Qty(header.blobGasUsed)
|
||||
result.excessBlobGas = w3Qty(header.excessBlobGas)
|
||||
result.requestsHash = header.requestsHash
|
||||
|
||||
proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction,
|
||||
txIndex: uint64, header: Header): ReceiptObject =
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
# Nimbus
|
||||
# Copyright (c) 2024 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
eth/common/[eth_types, eth_types_rlp, transaction_utils],
|
||||
web3/eth_api_types,
|
||||
../constants,
|
||||
../transaction
|
||||
|
||||
from ../beacon/web3_eth_conv import w3Qty
|
||||
|
||||
proc toWd(wd: eth_types.Withdrawal): WithdrawalObject =
|
||||
WithdrawalObject(
|
||||
index: Quantity(wd.index),
|
||||
validatorIndex: Quantity wd.validatorIndex,
|
||||
address: wd.address,
|
||||
amount: Quantity wd.amount,
|
||||
)
|
||||
|
||||
proc toWdList(list: openArray[eth_types.Withdrawal]): seq[WithdrawalObject] =
|
||||
result = newSeqOfCap[WithdrawalObject](list.len)
|
||||
for x in list:
|
||||
result.add toWd(x)
|
||||
|
||||
func toWdList(x: Opt[seq[eth_types.Withdrawal]]):
|
||||
Opt[seq[WithdrawalObject]] =
|
||||
if x.isNone: Opt.none(seq[WithdrawalObject])
|
||||
else: Opt.some(toWdList x.get)
|
||||
|
||||
proc populateTransactionObject*(tx: Transaction,
|
||||
optionalHash: Opt[eth_types.Hash32] = Opt.none(eth_types.Hash32),
|
||||
optionalNumber: Opt[eth_types.BlockNumber] = Opt.none(eth_types.BlockNumber),
|
||||
txIndex: Opt[uint64] = Opt.none(uint64)): TransactionObject =
|
||||
result = TransactionObject()
|
||||
result.`type` = Opt.some Quantity(tx.txType)
|
||||
result.blockHash = optionalHash
|
||||
result.blockNumber = w3Qty(optionalNumber)
|
||||
|
||||
if (let sender = tx.recoverSender(); sender.isOk):
|
||||
result.`from` = sender[]
|
||||
result.gas = Quantity(tx.gasLimit)
|
||||
result.gasPrice = Quantity(tx.gasPrice)
|
||||
result.hash = tx.rlpHash
|
||||
result.input = tx.payload
|
||||
result.nonce = Quantity(tx.nonce)
|
||||
result.to = Opt.some(tx.destination)
|
||||
if txIndex.isSome:
|
||||
result.transactionIndex = Opt.some(Quantity(txIndex.get))
|
||||
result.value = tx.value
|
||||
result.v = Quantity(tx.V)
|
||||
result.r = tx.R
|
||||
result.s = tx.S
|
||||
result.maxFeePerGas = Opt.some Quantity(tx.maxFeePerGas)
|
||||
result.maxPriorityFeePerGas = Opt.some Quantity(tx.maxPriorityFeePerGas)
|
||||
|
||||
if tx.txType >= TxEip2930:
|
||||
result.chainId = Opt.some(Quantity(tx.chainId))
|
||||
result.accessList = Opt.some(tx.accessList)
|
||||
|
||||
if tx.txType >= TxEip4844:
|
||||
result.maxFeePerBlobGas = Opt.some(tx.maxFeePerBlobGas)
|
||||
result.blobVersionedHashes = Opt.some(tx.versionedHashes)
|
||||
|
||||
proc populateBlockObject*(blockHash: eth_types.Hash32,
|
||||
blk: Block,
|
||||
fullTx: bool): BlockObject =
|
||||
template header: auto = blk.header
|
||||
|
||||
result = BlockObject()
|
||||
result.number = Quantity(header.number)
|
||||
result.hash = blockHash
|
||||
result.parentHash = header.parentHash
|
||||
result.nonce = Opt.some(header.nonce)
|
||||
result.sha3Uncles = header.ommersHash
|
||||
result.logsBloom = header.logsBloom
|
||||
result.transactionsRoot = header.txRoot
|
||||
result.stateRoot = header.stateRoot
|
||||
result.receiptsRoot = header.receiptsRoot
|
||||
result.miner = header.coinbase
|
||||
result.difficulty = header.difficulty
|
||||
result.extraData = HistoricExtraData header.extraData
|
||||
result.mixHash = Hash32 header.mixHash
|
||||
|
||||
# discard sizeof(seq[byte]) of extraData and use actual length
|
||||
let size = sizeof(eth_types.Header) - sizeof(eth_api_types.Blob) + header.extraData.len
|
||||
result.size = Quantity(size)
|
||||
|
||||
result.gasLimit = Quantity(header.gasLimit)
|
||||
result.gasUsed = Quantity(header.gasUsed)
|
||||
result.timestamp = Quantity(header.timestamp)
|
||||
result.baseFeePerGas = header.baseFeePerGas
|
||||
|
||||
if fullTx:
|
||||
for i, tx in blk.transactions:
|
||||
let txObj = populateTransactionObject(tx,
|
||||
Opt.some(blockHash),
|
||||
Opt.some(header.number), Opt.some(i.uint64))
|
||||
result.transactions.add txOrHash(txObj)
|
||||
else:
|
||||
for i, tx in blk.transactions:
|
||||
let txHash = rlpHash(tx)
|
||||
result.transactions.add txOrHash(txHash)
|
||||
|
||||
result.withdrawalsRoot = header.withdrawalsRoot
|
||||
result.withdrawals = toWdList blk.withdrawals
|
||||
result.parentBeaconBlockRoot = header.parentBeaconBlockRoot
|
||||
result.blobGasUsed = w3Qty(header.blobGasUsed)
|
||||
result.excessBlobGas = w3Qty(header.excessBlobGas)
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
std/[atomics, json, os, strutils, net],
|
||||
std/[atomics, json, strutils, net],
|
||||
../nimbus_verified_proxy,
|
||||
../nimbus_verified_proxy_conf
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import
|
|||
beacon_chain/spec/beaconstate,
|
||||
beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
|
||||
beacon_chain/[light_client, nimbus_binary_common, version],
|
||||
../nimbus/rpc/[cors, server_api_helpers],
|
||||
../nimbus/rpc/[cors, rpc_utils],
|
||||
../nimbus/beacon/payload_conv,
|
||||
./rpc/rpc_eth_api,
|
||||
./nimbus_verified_proxy_conf,
|
||||
|
@ -147,7 +147,7 @@ proc run*(
|
|||
parentBeaconBlockRoot = Opt.none(Hash32),
|
||||
requestsHash = Opt.none(Hash32),
|
||||
)
|
||||
blockCache.add(populateBlockObject(blk.header.rlpHash, blk, true))
|
||||
blockCache.add(populateBlockObject(blk.header.rlpHash, blk, 0.u256, true))
|
||||
except RlpError as exc:
|
||||
debug "Invalid block received", err = exc.msg
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 40854fb51fd444b7537da767800fbca2189eb2b7
|
||||
Subproject commit ff92d2877985faee5ac6abc3bea805b85f2be1c8
|
Loading…
Reference in New Issue