mirror of
https://github.com/status-im/nim-ethers.git
synced 2025-01-12 08:34:43 +00:00
Test JSON-RPC Provider with polling
This commit is contained in:
parent
0322ae1451
commit
88d60b14b0
@ -7,126 +7,123 @@ import pkg/stew/byteutils
|
|||||||
import ../../examples
|
import ../../examples
|
||||||
import ../../miner
|
import ../../miner
|
||||||
|
|
||||||
suite "JsonRpcProvider":
|
for url in ["ws://localhost:8545", "http://localhost:8545"]:
|
||||||
|
|
||||||
var provider: JsonRpcProvider
|
suite "JsonRpcProvider (" & url & ")":
|
||||||
|
|
||||||
setup:
|
var provider: JsonRpcProvider
|
||||||
provider = JsonRpcProvider.new("ws://localhost:8545")
|
|
||||||
|
|
||||||
test "can be instantiated with a default URL":
|
setup:
|
||||||
discard JsonRpcProvider.new()
|
provider = JsonRpcProvider.new(url)
|
||||||
|
|
||||||
test "can be instantiated with an HTTP URL":
|
test "can be instantiated with a default URL":
|
||||||
discard JsonRpcProvider.new("http://localhost:8545")
|
discard JsonRpcProvider.new()
|
||||||
|
|
||||||
test "can be instantiated with a websocket URL":
|
test "lists all accounts":
|
||||||
discard JsonRpcProvider.new("ws://localhost:8545")
|
let accounts = await provider.listAccounts()
|
||||||
|
check accounts.len > 0
|
||||||
|
|
||||||
test "lists all accounts":
|
test "sends raw messages to the provider":
|
||||||
let accounts = await provider.listAccounts()
|
let response = await provider.send("evm_mine")
|
||||||
check accounts.len > 0
|
check response == %"0x0"
|
||||||
|
|
||||||
test "sends raw messages to the provider":
|
test "returns block number":
|
||||||
let response = await provider.send("evm_mine")
|
let blocknumber1 = await provider.getBlockNumber()
|
||||||
check response == %"0x0"
|
discard await provider.send("evm_mine")
|
||||||
|
let blocknumber2 = await provider.getBlockNumber()
|
||||||
|
check blocknumber2 > blocknumber1
|
||||||
|
|
||||||
test "returns block number":
|
test "returns block":
|
||||||
let blocknumber1 = await provider.getBlockNumber()
|
let block1 = !await provider.getBlock(BlockTag.earliest)
|
||||||
discard await provider.send("evm_mine")
|
let block2 = !await provider.getBlock(BlockTag.latest)
|
||||||
let blocknumber2 = await provider.getBlockNumber()
|
check block1.hash != block2.hash
|
||||||
check blocknumber2 > blocknumber1
|
check !block1.number < !block2.number
|
||||||
|
check block1.timestamp < block2.timestamp
|
||||||
|
|
||||||
test "returns block":
|
test "subscribes to new blocks":
|
||||||
let block1 = !await provider.getBlock(BlockTag.earliest)
|
let oldBlock = !await provider.getBlock(BlockTag.latest)
|
||||||
let block2 = !await provider.getBlock(BlockTag.latest)
|
var newBlock: Block
|
||||||
check block1.hash != block2.hash
|
let blockHandler = proc(blck: Block) {.async.} = newBlock = blck
|
||||||
check !block1.number < !block2.number
|
let subscription = await provider.subscribe(blockHandler)
|
||||||
check block1.timestamp < block2.timestamp
|
discard await provider.send("evm_mine")
|
||||||
|
check eventually newBlock.number.isSome
|
||||||
|
check !newBlock.number > !oldBlock.number
|
||||||
|
check newBlock.timestamp > oldBlock.timestamp
|
||||||
|
check newBlock.hash != oldBlock.hash
|
||||||
|
await subscription.unsubscribe()
|
||||||
|
|
||||||
test "subscribes to new blocks":
|
test "can send a transaction":
|
||||||
let oldBlock = !await provider.getBlock(BlockTag.latest)
|
let signer = provider.getSigner()
|
||||||
var newBlock: Block
|
let transaction = Transaction.example
|
||||||
let blockHandler = proc(blck: Block) {.async.} = newBlock = blck
|
let populated = await signer.populateTransaction(transaction)
|
||||||
let subscription = await provider.subscribe(blockHandler)
|
|
||||||
discard await provider.send("evm_mine")
|
|
||||||
check !newBlock.number > !oldBlock.number
|
|
||||||
check newBlock.timestamp > oldBlock.timestamp
|
|
||||||
check newBlock.hash != oldBlock.hash
|
|
||||||
await subscription.unsubscribe()
|
|
||||||
|
|
||||||
test "can send a transaction":
|
let txResp = await signer.sendTransaction(populated)
|
||||||
let signer = provider.getSigner()
|
check txResp.hash.len == 32
|
||||||
let transaction = Transaction.example
|
check UInt256.fromHex("0x" & txResp.hash.toHex) > 0
|
||||||
let populated = await signer.populateTransaction(transaction)
|
|
||||||
|
|
||||||
let txResp = await signer.sendTransaction(populated)
|
test "can wait for a transaction to be confirmed":
|
||||||
check txResp.hash.len == 32
|
let signer = provider.getSigner()
|
||||||
check UInt256.fromHex("0x" & txResp.hash.toHex) > 0
|
let transaction = Transaction.example
|
||||||
|
let populated = await signer.populateTransaction(transaction)
|
||||||
|
|
||||||
test "can wait for a transaction to be confirmed":
|
# must not be awaited so we can get newHeads inside of .wait
|
||||||
let signer = provider.getSigner()
|
let futMined = provider.mineBlocks(5)
|
||||||
let transaction = Transaction.example
|
|
||||||
let populated = await signer.populateTransaction(transaction)
|
|
||||||
|
|
||||||
# must not be awaited so we can get newHeads inside of .wait
|
|
||||||
let futMined = provider.mineBlocks(5)
|
|
||||||
|
|
||||||
let receipt = await signer.sendTransaction(populated).confirm(3)
|
|
||||||
let endBlock = await provider.getBlockNumber()
|
|
||||||
|
|
||||||
check receipt.blockNumber.isSome # was eventually mined
|
|
||||||
|
|
||||||
# >= 3 because more blocks may have been mined by the time the
|
|
||||||
# check in `.wait` was done.
|
|
||||||
# +1 for the block the tx was mined in
|
|
||||||
check (endBlock - !receipt.blockNumber) + 1 >= 3
|
|
||||||
|
|
||||||
await futMined
|
|
||||||
|
|
||||||
test "waiting for block to be mined times out":
|
|
||||||
|
|
||||||
# must not be awaited so we can get newHeads inside of .wait
|
|
||||||
let futMined = provider.mineBlocks(7)
|
|
||||||
|
|
||||||
let startBlock = await provider.getBlockNumber()
|
|
||||||
let response = TransactionResponse(hash: TransactionHash.example,
|
|
||||||
provider: provider)
|
|
||||||
try:
|
|
||||||
discard await response.confirm(wantedConfirms = 2,
|
|
||||||
timeoutInBlocks = 5)
|
|
||||||
|
|
||||||
await futMined
|
|
||||||
except EthersError as e:
|
|
||||||
check e.msg == "Transaction was not mined in 5 blocks"
|
|
||||||
|
|
||||||
|
let receipt = await signer.sendTransaction(populated).confirm(3)
|
||||||
let endBlock = await provider.getBlockNumber()
|
let endBlock = await provider.getBlockNumber()
|
||||||
|
|
||||||
# >= 5 because more blocks may have been mined by the time the
|
check receipt.blockNumber.isSome # was eventually mined
|
||||||
|
|
||||||
|
# >= 3 because more blocks may have been mined by the time the
|
||||||
# check in `.wait` was done.
|
# check in `.wait` was done.
|
||||||
# +1 for including the start block
|
# +1 for the block the tx was mined in
|
||||||
check (endBlock - startBlock) + 1 >= 5 # +1 including start block
|
check (endBlock - !receipt.blockNumber) + 1 >= 3
|
||||||
if not futMined.completed and not futMined.finished: await futMined
|
|
||||||
|
|
||||||
test "Conversion: missing block number in Block isNone":
|
await futMined
|
||||||
|
|
||||||
var blkJson = %*{
|
test "waiting for block to be mined times out":
|
||||||
"subscription": "0x20",
|
|
||||||
"result":{
|
# must not be awaited so we can get newHeads inside of .wait
|
||||||
"number": newJNull(),
|
let futMined = provider.mineBlocks(7)
|
||||||
"hash":"0x2d7d68c8f48b4213d232a1f12cab8c9fac6195166bb70a5fb21397984b9fe1c7",
|
|
||||||
"timestamp":"0x6285c293"
|
let startBlock = await provider.getBlockNumber()
|
||||||
|
let response = TransactionResponse(hash: TransactionHash.example,
|
||||||
|
provider: provider)
|
||||||
|
try:
|
||||||
|
discard await response.confirm(wantedConfirms = 2,
|
||||||
|
timeoutInBlocks = 5)
|
||||||
|
|
||||||
|
await futMined
|
||||||
|
except EthersError as e:
|
||||||
|
check e.msg == "Transaction was not mined in 5 blocks"
|
||||||
|
|
||||||
|
let endBlock = await provider.getBlockNumber()
|
||||||
|
|
||||||
|
# >= 5 because more blocks may have been mined by the time the
|
||||||
|
# check in `.wait` was done.
|
||||||
|
# +1 for including the start block
|
||||||
|
check (endBlock - startBlock) + 1 >= 5 # +1 including start block
|
||||||
|
if not futMined.completed and not futMined.finished: await futMined
|
||||||
|
|
||||||
|
test "Conversion: missing block number in Block isNone":
|
||||||
|
|
||||||
|
var blkJson = %*{
|
||||||
|
"subscription": "0x20",
|
||||||
|
"result":{
|
||||||
|
"number": newJNull(),
|
||||||
|
"hash":"0x2d7d68c8f48b4213d232a1f12cab8c9fac6195166bb70a5fb21397984b9fe1c7",
|
||||||
|
"timestamp":"0x6285c293"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var blk = Block.fromJson(blkJson["result"])
|
var blk = Block.fromJson(blkJson["result"])
|
||||||
check blk.number.isNone
|
check blk.number.isNone
|
||||||
|
|
||||||
blkJson["result"]["number"] = newJString("")
|
blkJson["result"]["number"] = newJString("")
|
||||||
|
|
||||||
blk = Block.fromJson(blkJson["result"])
|
blk = Block.fromJson(blkJson["result"])
|
||||||
check blk.number.isSome
|
check blk.number.isSome
|
||||||
check blk.number.get.isZero
|
check blk.number.get.isZero
|
||||||
|
|
||||||
test "Conversion: missing block hash in Block isNone":
|
test "Conversion: missing block hash in Block isNone":
|
||||||
|
|
||||||
@ -142,132 +139,132 @@ suite "JsonRpcProvider":
|
|||||||
var blk = Block.fromJson(blkJson["result"])
|
var blk = Block.fromJson(blkJson["result"])
|
||||||
check blk.hash.isNone
|
check blk.hash.isNone
|
||||||
|
|
||||||
test "Conversion: missing block number in TransactionReceipt isNone":
|
test "Conversion: missing block number in TransactionReceipt isNone":
|
||||||
|
|
||||||
var txReceiptJson = %*{
|
var txReceiptJson = %*{
|
||||||
"sender": newJNull(),
|
"sender": newJNull(),
|
||||||
"to": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
|
"to": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
|
||||||
"contractAddress": newJNull(),
|
"contractAddress": newJNull(),
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"gasUsed": "0x10db1",
|
"gasUsed": "0x10db1",
|
||||||
"logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000840020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000020000000000000000000000000000000000001000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000840020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000020000000000000000000000000000000000001000000000000000000000000000000",
|
||||||
"blockHash": "0x7b00154e06fe4f27a87208eba220efb4dbc52f7429549a39a17bba2e0d98b960",
|
"blockHash": "0x7b00154e06fe4f27a87208eba220efb4dbc52f7429549a39a17bba2e0d98b960",
|
||||||
"transactionHash": "0xa64f07b370cbdcce381ec9bfb6c8004684341edfb6848fd418189969d4b9139c",
|
"transactionHash": "0xa64f07b370cbdcce381ec9bfb6c8004684341edfb6848fd418189969d4b9139c",
|
||||||
"logs": [
|
"logs": [
|
||||||
{
|
{
|
||||||
"data": "0x0000000000000000000000000000000000000000000000000000000000000064",
|
"data": "0x0000000000000000000000000000000000000000000000000000000000000064",
|
||||||
"topics": [
|
"topics": [
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8"
|
"0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"blockNumber": newJNull(),
|
"blockNumber": newJNull(),
|
||||||
"cumulativeGasUsed": "0x10db1",
|
"cumulativeGasUsed": "0x10db1",
|
||||||
"status": "0000000000000001"
|
"status": "0000000000000001"
|
||||||
}
|
}
|
||||||
|
|
||||||
var txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
var txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
||||||
check txReceipt.blockNumber.isNone
|
check txReceipt.blockNumber.isNone
|
||||||
|
|
||||||
txReceiptJson["blockNumber"] = newJString("")
|
txReceiptJson["blockNumber"] = newJString("")
|
||||||
txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
||||||
check txReceipt.blockNumber.isSome
|
check txReceipt.blockNumber.isSome
|
||||||
check txReceipt.blockNumber.get.isZero
|
check txReceipt.blockNumber.get.isZero
|
||||||
|
|
||||||
test "Conversion: missing block hash in TransactionReceipt isNone":
|
test "Conversion: missing block hash in TransactionReceipt isNone":
|
||||||
|
|
||||||
var txReceiptJson = %*{
|
var txReceiptJson = %*{
|
||||||
"sender": newJNull(),
|
"sender": newJNull(),
|
||||||
"to": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
|
"to": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
|
||||||
"contractAddress": newJNull(),
|
"contractAddress": newJNull(),
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"gasUsed": "0x10db1",
|
"gasUsed": "0x10db1",
|
||||||
"logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000840020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000020000000000000000000000000000000000001000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000840020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000020000000000000000000000000000000000001000000000000000000000000000000",
|
||||||
"blockHash": newJNull(),
|
"blockHash": newJNull(),
|
||||||
"transactionHash": "0xa64f07b370cbdcce381ec9bfb6c8004684341edfb6848fd418189969d4b9139c",
|
"transactionHash": "0xa64f07b370cbdcce381ec9bfb6c8004684341edfb6848fd418189969d4b9139c",
|
||||||
"logs": [
|
"logs": [
|
||||||
{
|
{
|
||||||
"data": "0x0000000000000000000000000000000000000000000000000000000000000064",
|
"data": "0x0000000000000000000000000000000000000000000000000000000000000064",
|
||||||
"topics": [
|
"topics": [
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8"
|
"0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"blockNumber": newJNull(),
|
"blockNumber": newJNull(),
|
||||||
"cumulativeGasUsed": "0x10db1",
|
"cumulativeGasUsed": "0x10db1",
|
||||||
"status": "0000000000000001"
|
"status": "0000000000000001"
|
||||||
}
|
}
|
||||||
|
|
||||||
var txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
var txReceipt = TransactionReceipt.fromJson(txReceiptJson)
|
||||||
check txReceipt.blockHash.isNone
|
check txReceipt.blockHash.isNone
|
||||||
|
|
||||||
test "confirmations calculated correctly":
|
test "confirmations calculated correctly":
|
||||||
# when receipt block number is higher than current block number,
|
# when receipt block number is higher than current block number,
|
||||||
# should return 0
|
# should return 0
|
||||||
check confirmations(2.u256, 1.u256) == 0.u256
|
check confirmations(2.u256, 1.u256) == 0.u256
|
||||||
|
|
||||||
# Same receipt and current block counts as one confirmation
|
# Same receipt and current block counts as one confirmation
|
||||||
check confirmations(1.u256, 1.u256) == 1.u256
|
check confirmations(1.u256, 1.u256) == 1.u256
|
||||||
|
|
||||||
check confirmations(1.u256, 2.u256) == 2.u256
|
check confirmations(1.u256, 2.u256) == 2.u256
|
||||||
|
|
||||||
test "checks if transation has been mined correctly":
|
test "checks if transation has been mined correctly":
|
||||||
|
|
||||||
var receipt: TransactionReceipt
|
var receipt: TransactionReceipt
|
||||||
var currentBlock = 1.u256
|
var currentBlock = 1.u256
|
||||||
var wantedConfirms = 1
|
var wantedConfirms = 1
|
||||||
let blockHash = hexToByteArray[32](
|
let blockHash = hexToByteArray[32](
|
||||||
"0x7b00154e06fe4f27a87208eba220efb4dbc52f7429549a39a17bba2e0d98b960"
|
"0x7b00154e06fe4f27a87208eba220efb4dbc52f7429549a39a17bba2e0d98b960"
|
||||||
).some
|
).some
|
||||||
|
|
||||||
# missing blockHash
|
# missing blockHash
|
||||||
receipt = TransactionReceipt(
|
receipt = TransactionReceipt(
|
||||||
blockNumber: 1.u256.some
|
blockNumber: 1.u256.some
|
||||||
)
|
)
|
||||||
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
||||||
|
|
||||||
# missing block number
|
# missing block number
|
||||||
receipt = TransactionReceipt(
|
receipt = TransactionReceipt(
|
||||||
blockHash: blockHash
|
blockHash: blockHash
|
||||||
)
|
)
|
||||||
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
||||||
|
|
||||||
# block number is 0
|
# block number is 0
|
||||||
receipt = TransactionReceipt(
|
receipt = TransactionReceipt(
|
||||||
blockNumber: 0.u256.some
|
blockNumber: 0.u256.some
|
||||||
)
|
)
|
||||||
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
||||||
|
|
||||||
# not enough confirms
|
# not enough confirms
|
||||||
receipt = TransactionReceipt(
|
receipt = TransactionReceipt(
|
||||||
blockNumber: 1.u256.some
|
blockNumber: 1.u256.some
|
||||||
)
|
)
|
||||||
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
check not receipt.hasBeenMined(currentBlock, wantedConfirms)
|
||||||
|
|
||||||
# success
|
# success
|
||||||
receipt = TransactionReceipt(
|
receipt = TransactionReceipt(
|
||||||
blockNumber: 1.u256.some,
|
blockNumber: 1.u256.some,
|
||||||
blockHash: blockHash
|
blockHash: blockHash
|
||||||
)
|
)
|
||||||
currentBlock = int.high.u256
|
currentBlock = int.high.u256
|
||||||
wantedConfirms = int.high
|
wantedConfirms = int.high
|
||||||
check receipt.hasBeenMined(currentBlock, wantedConfirms)
|
check receipt.hasBeenMined(currentBlock, wantedConfirms)
|
||||||
|
|
||||||
test "raises JsonRpcProviderError when something goes wrong":
|
test "raises JsonRpcProviderError when something goes wrong":
|
||||||
let provider = JsonRpcProvider.new("http://invalid.")
|
let provider = JsonRpcProvider.new("http://invalid.")
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.listAccounts()
|
discard await provider.listAccounts()
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.send("evm_mine")
|
discard await provider.send("evm_mine")
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.getBlockNumber()
|
discard await provider.getBlockNumber()
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.getBlock(BlockTag.latest)
|
discard await provider.getBlock(BlockTag.latest)
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.subscribe(proc(_: Block) {.async.} = discard)
|
discard await provider.subscribe(proc(_: Block) {.async.} = discard)
|
||||||
expect JsonRpcProviderError:
|
expect JsonRpcProviderError:
|
||||||
discard await provider.getSigner().sendTransaction(Transaction.example)
|
discard await provider.getSigner().sendTransaction(Transaction.example)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user