From c3d4029a9c80d333d3217193450f98cfcdaa8d91 Mon Sep 17 00:00:00 2001 From: PMunch Date: Mon, 7 Jan 2019 17:59:57 +0100 Subject: [PATCH] Started work on event loop and callback structure --- src/ethcallsigs.nim | 2 +- src/ethtypes.nim | 22 ++++++++++++++++++---- src/web3.nim | 41 +++++++++++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/ethcallsigs.nim b/src/ethcallsigs.nim index f72d507..507e2e4 100644 --- a/src/ethcallsigs.nim +++ b/src/ethcallsigs.nim @@ -15,7 +15,7 @@ proc eth_mining(): bool proc eth_hashrate(): int proc eth_gasPrice(): int64 proc eth_accounts(): seq[array[20, byte]] -proc eth_blockNumber(): int +proc eth_blockNumber(): string proc eth_getBalance(data: array[20, byte], quantityTag: string): int proc eth_getStorageAt(data: array[20, byte], quantity: int, quantityTag: string): seq[byte] proc eth_getTransactionCount(data: array[20, byte], quantityTag: string) diff --git a/src/ethtypes.nim b/src/ethtypes.nim index 883e49b..c97f420 100644 --- a/src/ethtypes.nim +++ b/src/ethtypes.nim @@ -102,10 +102,10 @@ type # TODO: I don't think this will work as input, need only one value that is either UInt256 or seq[UInt256] FilterOptions* = object - fromBlock*: string # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions. - toBlock*: string # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions. - address*: seq[array[20, byte]] # (optional) contract address or a list of addresses from which logs should originate. - topics*: seq[FilterData] # (optional) list of DATA topics. Topics are order-dependent. Each topic can also be a list of DATA with "or" options. + fromBlock*: Option[string] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions. + toBlock*: Option[string] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions. + address*: Option[string] # (optional) contract address or a list of addresses from which logs should originate. + topics*: Option[seq[string]]#Option[seq[FilterData]] # (optional) list of DATA topics. Topics are order-dependent. Each topic can also be a list of DATA with "or" options. LogObject* = object #removed*: bool # true when the log was removed, due to a chain reorganization. false if its a valid log. @@ -189,3 +189,17 @@ proc `%`*(x: EthCall): JsonNode = result["value"] = %x.value.unsafeGet if x.data.isSome: result["data"] = %x.data.unsafeGet + +proc `%`*(x: byte): JsonNode = + %x.int + +proc `%`*(x: FilterOptions): JsonNode = + result = newJobject() + if x.fromBlock.isSome: + result["fromBlock"] = %x.fromBlock.unsafeGet + if x.toBlock.isSome: + result["toBlock"] = %x.toBlock.unsafeGet + if x.address.isSome: + result["address"] = %x.address.unsafeGet + if x.topics.isSome: + result["topics"] = %x.topics.unsafeGet diff --git a/src/web3.nim b/src/web3.nim index ab0fb45..80b875c 100644 --- a/src/web3.nim +++ b/src/web3.nim @@ -1,5 +1,5 @@ import macros, strutils, options, math, json -from os import getCurrentDir, DirSep +from os import getCurrentDir, DirSep, sleep import nimcrypto, stint, httputils, chronicles, asyncdispatch2, json_rpc/rpcclient import ethtypes, ethprocs, stintjson, ethhexstrings @@ -286,9 +286,16 @@ proc parseContract(body: NimNode): seq[InterfaceObject] = macro contract(cname: untyped, body: untyped): untyped = var objects = parseContract(body) result = newStmtList() + let address = ident "address" result.add quote do: type - `cname` = distinct Contract + #`cname` = distinct Contract + `cname` = ref object + `address`: array[20, byte] + #callbacks: tuple[ + # Transfer: seq[proc (fromAddr: Address, toAddr: Address, value: Uint256)] + #] + for obj in objects: if obj.kind == function: echo obj.functionObject.outputs @@ -328,7 +335,8 @@ macro contract(cname: untyped, body: untyped): untyped = procDef[6].add quote do: var cc: EthCall cc.source = some(`senderName`.address) - cc.to = `senderName`.contract.Contract.address + #cc.to = `senderName`.contract.Contract.address + cc.to = `senderName`.contract.address cc.data = some("0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`) let response = waitFor `client`.eth_call(cc, "latest") return response @@ -336,7 +344,8 @@ macro contract(cname: untyped, body: untyped): untyped = procDef[6].add quote do: var cc: EthSend cc.source = `senderName`.address - cc.to = some(`senderName`.contract.Contract.address) + #cc.to = some(`senderName`.contract.Contract.address) + cc.to = some(`senderName`.contract.address) cc.data = "0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams` let response = waitFor `client`.eth_sendTransaction(cc) return response @@ -393,7 +402,26 @@ macro toAddress(input: string): untyped = ident "byte" ) -var x = Contract(address: "254dffcd3277C0b1660F6d42EFbB754edaBAbC2B".toAddress).TestContract +proc eventListen(callback: proc(receipt: LogObject)) = + var client = newRpcHttpClient() + client.httpMethod(MethodPost) + waitFor client.connect("127.0.0.1", Port(8545)) + var lastBlock = "0x" & (parseHexInt((waitFor client.eth_blockNumber())[2..^1]) + 1).toHex[^2..^1] + while true: + waitFor client.connect("127.0.0.1", Port(8545)) + let response = waitFor client.eth_getLogs(FilterOptions(fromBlock: some(lastBlock), toBlock: none(string), address: some("0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B".toLower), topics: none(seq[string]))) + if response.len > 0: + lastBlock = "0x" & (parseHexInt(response[^1].blockNumber[2..^1]) + 1).toHex[^2..^1] + for receipt in response: + callback(receipt) + sleep(1000) + +var thr: Thread[proc(receipt: LogObject)] +createThread(thr, eventListen, proc(receipt: LogObject) = + echo receipt +) + +var x = TestContract(address: "254dffcd3277C0b1660F6d42EFbB754edaBAbC2B".toAddress)#.TestContract echo x.sender("127.0.0.1", 8545, "90f8bf6a479f320ead074411a4b0e7944ea8c9c1".toAddress).getBalance( fromHex(Stuint[256], "ffcf8fdee72ac11b5c542428b35eef5769c409f0") @@ -401,10 +429,11 @@ echo x.sender("127.0.0.1", 8545, "90f8bf6a479f320ead074411a4b0e7944ea8c9c1".toAd echo toHex(x.sender("127.0.0.1", 8545, "90f8bf6a479f320ead074411a4b0e7944ea8c9c1".toAddress).sendCoin( fromHex(Stuint[256], "ffcf8fdee72ac11b5c542428b35eef5769c409f0"), - 100000.to(Stuint[256]) + 256.to(Stuint[256]) )) echo x.sender("127.0.0.1", 8545, "90f8bf6a479f320ead074411a4b0e7944ea8c9c1".toAddress).getBalance( fromHex(Stuint[256], "ffcf8fdee72ac11b5c542428b35eef5769c409f0") ) #echo "0x" & $keccak_256.digest("Transfer(address,address,uint256)") +joinThreads([thr])