diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelector.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelector.kt index acbac60a..8d548a11 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelector.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelector.kt @@ -61,24 +61,37 @@ class EthereumCallSelector { log.debug("Tag is not specified. Ignoring") return null } - // integer block number, or the string "latest", "earliest" or "pending" - val minHeight = when (val tag = list[pos].toString()) { - "latest" -> head.getCurrentHeight() ?: 0 + // integer block number, a string "latest", "earliest" or "pending", or an object with block reference + val minHeight: Long? = when (val tag = list[pos].toString()) { + "latest" -> head.getCurrentHeight() // for earliest it doesn't nothing, we expect to have 0 block "earliest" -> 0L else -> if (tag.startsWith("0x")) { + try { + HexQuantity.from(tag).value.toLong() + } catch (t: Throwable) { + log.debug("Invalid tag: $tag. ${t.javaClass}: ${t.message}") + null + } + } else if (tag.startsWith("{") && list[pos] is Map<*, *>) { + // see https://eips.ethereum.org/EIPS/eip-1898 + val obj = list[pos] as Map<*, *> + if (obj.containsKey("blockNumber")) { try { - HexQuantity.from(tag).value.toLong() + HexQuantity.from(obj["blockNumber"].toString()).value.toLong() } catch (t: Throwable) { - log.debug("Invalid tag: $tag. ${t.javaClass}: ${t.message}") - 0L + log.warn("Invalid blockNumber: $tag") + null } } else { - log.debug("Invalid tag: $tag") - 0L + null } + } else { + log.debug("Invalid tag: $tag") + null + } } - return if (minHeight > 0) { + return if (minHeight != null && minHeight >= 0) { Selector.HeightMatcher(minHeight) } else { null diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelectorSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelectorSpec.groovy index b7b81d47..972b7b1e 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelectorSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/EthereumCallSelectorSpec.groovy @@ -78,4 +78,12 @@ class EthereumCallSelectorSpec extends Specification { act == null } + def "Get height matcher with EIP-1898"() { + setup: + def head = Stub(Head) + when: + def act = callSelector.getMatcher("eth_call", '["0x0000", {"blockNumber": "0x100"}]', head) + then: + act == new Selector.HeightMatcher(0x100) + } }