Add height matcher for method (#156)
* add height matcher for method * add test * add test for block methods fix
This commit is contained in:
@@ -63,13 +63,15 @@ class EthereumCallSelector(
|
|||||||
*/
|
*/
|
||||||
fun getMatcher(method: String, params: String, head: Head, passthrough: Boolean): Mono<Selector.Matcher> {
|
fun getMatcher(method: String, params: String, head: Head, passthrough: Boolean): Mono<Selector.Matcher> {
|
||||||
if (!passthrough && Collections.binarySearch(TAG_METHODS, method) >= 0) {
|
if (!passthrough && Collections.binarySearch(TAG_METHODS, method) >= 0) {
|
||||||
return blockTagSelector(params, 1, head)
|
return blockTagSelector(params, 1, null, head)
|
||||||
} else if (!passthrough && method == "eth_getStorageAt") {
|
} else if (!passthrough && method == "eth_getStorageAt") {
|
||||||
return blockTagSelector(params, 2, head)
|
return blockTagSelector(params, 2, null, head)
|
||||||
} else if (method in DefaultEthereumMethods.withFilterIdMethods) {
|
} else if (method in DefaultEthereumMethods.withFilterIdMethods) {
|
||||||
return sameUpstreamMatcher(params)
|
return sameUpstreamMatcher(params)
|
||||||
} else if (method in GET_BY_HASH_OR_NUMBER_METHODS) {
|
} else if (method in GET_BY_HASH_OR_NUMBER_METHODS) {
|
||||||
return blockMethodSelector(method, params)
|
return blockMethodSelector(method, params, head)
|
||||||
|
} else if (method == "eth_getLogs") {
|
||||||
|
return blockTagSelector(params, 0, "toBlock", head)
|
||||||
}
|
}
|
||||||
return Mono.empty()
|
return Mono.empty()
|
||||||
}
|
}
|
||||||
@@ -87,36 +89,52 @@ class EthereumCallSelector(
|
|||||||
val nodeId = hashHex.toInt(16)
|
val nodeId = hashHex.toInt(16)
|
||||||
return Mono.just(Selector.SameNodeMatcher(nodeId.toByte()))
|
return Mono.just(Selector.SameNodeMatcher(nodeId.toByte()))
|
||||||
}
|
}
|
||||||
|
private fun blockTagSelector(params: String, pos: Int, paramName: String?, head: Head): Mono<Selector.Matcher> {
|
||||||
private fun blockTagSelector(params: String, pos: Int, head: Head): Mono<Selector.Matcher> {
|
|
||||||
val list = objectMapper.readerFor(Any::class.java).readValues<Any>(params).readAll()
|
val list = objectMapper.readerFor(Any::class.java).readValues<Any>(params).readAll()
|
||||||
if (list.size < pos + 1) {
|
if (list.size < pos + 1) {
|
||||||
log.debug("Tag is not specified. Ignoring")
|
log.debug("Tag is not specified. Ignoring")
|
||||||
return Mono.empty()
|
return Mono.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// integer block number, a string "latest", "earliest" or "pending", or an object with block reference
|
// integer block number, a string "latest", "earliest" or "pending", or an object with block reference
|
||||||
val minHeight: Long? = when (val tag = Objects.toString(list[pos])) {
|
val blockTag = Objects.toString(list[pos])
|
||||||
|
|
||||||
|
return if (blockTag.startsWith("{") && list[pos] is Map<*, *>) {
|
||||||
|
val obj = list[pos] as Map<*, *>
|
||||||
|
when {
|
||||||
|
paramName != null -> {
|
||||||
|
return if (obj.containsKey(paramName)) {
|
||||||
|
blockSelectorByTag(obj[paramName].toString(), head)
|
||||||
|
} else {
|
||||||
|
Mono.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.containsKey("blockNumber") -> {
|
||||||
|
return blockSelectorByTag(obj["blockNumber"].toString(), head)
|
||||||
|
}
|
||||||
|
obj.containsKey("blockHash") -> {
|
||||||
|
return blockSelectorByTag(obj["blockHash"].toString(), head)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
log.debug("Tag is not found. Ignoring")
|
||||||
|
Mono.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blockSelectorByTag(blockTag, head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun blockSelectorByTag(tag: String, head: Head): Mono<Selector.Matcher> {
|
||||||
|
val minHeight: Long? = when (tag) {
|
||||||
"latest" -> head.getCurrentHeight()
|
"latest" -> head.getCurrentHeight()
|
||||||
// for earliest it doesn't nothing, we expect to have 0 block
|
"earliest" -> 0L // for earliest it doesn't nothing, we expect to have 0 block
|
||||||
"earliest" -> 0L
|
|
||||||
else -> if (tag.startsWith("0x")) {
|
else -> if (tag.startsWith("0x")) {
|
||||||
return if (tag.length == 66) { // 32-byte hash is represented as 0x + 64 characters
|
return if (tag.length == 66) { // 32-byte hash is represented as 0x + 64 characters
|
||||||
blockByHash(tag, head)
|
blockByHash(tag, head)
|
||||||
} else {
|
} else {
|
||||||
blockByHeight(tag)
|
blockByHeight(tag)
|
||||||
}
|
}
|
||||||
} else if (tag.startsWith("{") && list[pos] is Map<*, *>) {
|
|
||||||
// see https://eips.ethereum.org/EIPS/eip-1898
|
|
||||||
val obj = list[pos] as Map<*, *>
|
|
||||||
when {
|
|
||||||
obj.containsKey("blockNumber") -> {
|
|
||||||
return blockByHeight(obj["blockNumber"].toString())
|
|
||||||
}
|
|
||||||
obj.containsKey("blockHash") -> {
|
|
||||||
return blockByHash(obj["blockHash"].toString(), head)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("Invalid tag: $tag")
|
log.debug("Invalid tag: $tag")
|
||||||
null
|
null
|
||||||
@@ -128,8 +146,7 @@ class EthereumCallSelector(
|
|||||||
Mono.empty()
|
Mono.empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private fun blockMethodSelector(method: String, params: String, head: Head): Mono<Selector.Matcher> {
|
||||||
private fun blockMethodSelector(method: String, params: String): Mono<Selector.Matcher> {
|
|
||||||
val list = objectMapper.readerFor(Any::class.java).readValues<Any>(params).readAll()
|
val list = objectMapper.readerFor(Any::class.java).readValues<Any>(params).readAll()
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return Mono.empty()
|
return Mono.empty()
|
||||||
@@ -138,7 +155,7 @@ class EthereumCallSelector(
|
|||||||
|
|
||||||
return when (method) {
|
return when (method) {
|
||||||
"eth_getTransactionByBlockHashAndIndex", "eth_getBlockByHash" -> blockByHashFromCache(hashOrNumber)
|
"eth_getTransactionByBlockHashAndIndex", "eth_getBlockByHash" -> blockByHashFromCache(hashOrNumber)
|
||||||
"eth_getTransactionByBlockNumberAndIndex", "eth_getBlockByNumber" -> blockByHeight(hashOrNumber)
|
"eth_getTransactionByBlockNumberAndIndex", "eth_getBlockByNumber" -> blockSelectorByTag(hashOrNumber, head)
|
||||||
else -> Mono.empty()
|
else -> Mono.empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,22 +264,29 @@ class EthereumCallSelectorSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def cache = Stub(Caches)
|
def cache = Stub(Caches)
|
||||||
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
|
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
|
||||||
def head = Stub(Head)
|
def head = Mock(Head) {
|
||||||
|
_ * getCurrentHeight() >> 17654321L
|
||||||
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = callSelector.getMatcher(
|
def act = callSelector.getMatcher(
|
||||||
method, '["0xfbfe3b", false]',
|
method, params, head, false
|
||||||
head, false
|
|
||||||
)
|
)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNext(new Selector.HeightMatcher(16514619L))
|
.expectNext(new Selector.HeightMatcher(height))
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
|
|
||||||
where:
|
where:
|
||||||
method << ["eth_getTransactionByBlockNumberAndIndex", "eth_getBlockByNumber"]
|
method | params | height
|
||||||
|
"eth_getTransactionByBlockNumberAndIndex" | '["0xfbfe3b", false]' | 16514619L
|
||||||
|
"eth_getTransactionByBlockNumberAndIndex" | '["earliest", false]' | 0L
|
||||||
|
"eth_getTransactionByBlockNumberAndIndex" | '["latest", false]' | 17654321L
|
||||||
|
"eth_getBlockByNumber" | '["0xfbfe3b", false]' | 16514619L
|
||||||
|
"eth_getBlockByNumber" | '["earliest", false]' | 0L
|
||||||
|
"eth_getBlockByNumber" | '["latest", false]' | 17654321L
|
||||||
}
|
}
|
||||||
|
|
||||||
def "No height matcher for getByHash method"() {
|
def "No height matcher for getByHash method"() {
|
||||||
@@ -307,4 +314,28 @@ class EthereumCallSelectorSpec extends Specification {
|
|||||||
where:
|
where:
|
||||||
resultFromCache << [Mono.empty(), Mono.error(new RuntimeException())]
|
resultFromCache << [Mono.empty(), Mono.error(new RuntimeException())]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Get height matcher for getLogs method"() {
|
||||||
|
setup:
|
||||||
|
def cache = Stub(Caches)
|
||||||
|
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
|
||||||
|
def head = Mock(Head) {
|
||||||
|
_ * getCurrentHeight() >> 17654321L
|
||||||
|
}
|
||||||
|
|
||||||
|
when:
|
||||||
|
def act = callSelector.getMatcher(method, param, head, false)
|
||||||
|
|
||||||
|
then:
|
||||||
|
StepVerifier.create(act)
|
||||||
|
.expectNext(new Selector.HeightMatcher(height))
|
||||||
|
.expectComplete()
|
||||||
|
.verify(Duration.ofSeconds(1))
|
||||||
|
|
||||||
|
where:
|
||||||
|
method | param | height
|
||||||
|
"eth_getLogs" | '[{"toBlock":"0xfbfe3b"}]' | 16514619L
|
||||||
|
"eth_getLogs" | '[{"toBlock":"latest"}]' | 17654321L
|
||||||
|
"eth_getLogs" | '[{"toBlock":"earliest"}]' | 0L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user