Argument decoding and initial deploy contract testing

This commit is contained in:
PMunch 2019-01-29 15:17:20 +01:00
parent 332b0ccfc8
commit aff05ca240
4 changed files with 79 additions and 26 deletions

View File

@ -9,7 +9,7 @@ contract(TestContract):
proc ChainStart(deposit_root: bytes32, time: bytes) {.event.} proc ChainStart(deposit_root: bytes32, time: bytes) {.event.}
proc deposit(deposit_input: bytes) {.payable.} proc deposit(deposit_input: bytes) {.payable.}
proc get_deposit_root(): bytes32 {.view.} proc get_deposit_root(): bytes32 {.view.}
#proc get_branch(leaf: uint256): bytes32[32] {.pure.} proc get_branch(leaf: uint256): bytes32[32] {.view.}
#var #var
# x2 = TestContract(address: # x2 = TestContract(address:
@ -21,13 +21,15 @@ contract(TestContract):
var var
x = TestContract(address: x = TestContract(address:
"4e7f73f0bbee44db86fbf8b957cf7c8bf330c2fe".toAddress, "630170976aBc526b1408Cc2Dd7b7B5599862c02f".toAddress,
client: newRpcHttpClient() client: newRpcHttpClient()
) )
sender = x.initSender("127.0.0.1", 8545, sender = x.initSender("127.0.0.1", 8545,
"45b6fc37a833d2f20dc25917f0a632f351be474b".toAddress) "c9f03520257dd207a159164c534c2b2664d8fd22".toAddress)
receiver = x.initReceiver("127.0.0.1", 8545) #receiver = x.initReceiver("127.0.0.1", 8545)
eventListener = receiver.initEventListener() #eventListener = receiver.initEventListener()
echo waitFor sender.getDepositRoot()
#x.callbacks.Transfer.add proc (fromAddr, toAddr: Address, value: Uint256) = #x.callbacks.Transfer.add proc (fromAddr, toAddr: Address, value: Uint256) =
# echo $value, " coins were transferred from ", fromAddr.toHex, " to ", toAddr.toHex # echo $value, " coins were transferred from ", fromAddr.toHex, " to ", toAddr.toHex
@ -52,4 +54,4 @@ var
# 10.to(Stuint[256]) # 10.to(Stuint[256])
#)) #))
waitFor eventListener.listen() #waitFor eventListener.listen()

View File

@ -27,7 +27,7 @@ proc eth_getCode(data: array[20, byte], quantityTag: string): seq[byte]
proc eth_sign(data: array[20, byte], message: seq[byte]): seq[byte] proc eth_sign(data: array[20, byte], message: seq[byte]): seq[byte]
proc eth_sendTransaction(obj: EthSend): UInt256 proc eth_sendTransaction(obj: EthSend): UInt256
proc eth_sendRawTransaction(data: string, quantityTag: int): UInt256 proc eth_sendRawTransaction(data: string, quantityTag: int): UInt256
proc eth_call(call: EthCall, quantityTag: string): seq[byte]#UInt256 proc eth_call(call: EthCall, quantityTag: string): string #UInt256
proc eth_estimateGas(call: EthCall, quantityTag: string): UInt256 proc eth_estimateGas(call: EthCall, quantityTag: string): UInt256
proc eth_getBlockByHash(data: array[32, byte], fullTransactions: bool): BlockObject proc eth_getBlockByHash(data: array[32, byte], fullTransactions: bool): BlockObject
proc eth_getBlockByNumber(quantityTag: string, fullTransactions: bool): BlockObject proc eth_getBlockByNumber(quantityTag: string, fullTransactions: bool): BlockObject

View File

@ -8,11 +8,6 @@ contract(TestContract):
proc sendCoin(receiver: Address, amount: Uint): Bool proc sendCoin(receiver: Address, amount: Uint): Bool
proc getBalance(address: Address): Uint {.view.} proc getBalance(address: Address): Uint {.view.}
proc Transfer(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256) {.event.} proc Transfer(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256) {.event.}
proc Deposit(previous_deposit_root: Bytes32, data: Byte[2064], merkle_tree_index: bytes[8]) {.event.}
proc ChainStart(deposit_root: bytes32, time: byte[8])
proc deposit(deposit_input: byte[2048]) {.payable.}
proc get_deposit_root(): bytes32 {.pure.}
proc get_branch(leaf: uint256): bytes32 {.pure.}
#var #var
# x2 = TestContract(address: # x2 = TestContract(address:

View File

@ -37,12 +37,12 @@ type
# result = new Web3 # result = new Web3
# result.eth = client # result.eth = client
func encode[bits: static[int]](x: Stuint[bits]): EncodeResult = func encode*[bits: static[int]](x: Stuint[bits]): EncodeResult =
## Encodes a `Stuint` to a textual representation for use in the JsonRPC ## Encodes a `Stuint` to a textual representation for use in the JsonRPC
## `sendTransaction` call. ## `sendTransaction` call.
(dynamic: false, data: '0'.repeat((256 - bits) div 4) & x.dumpHex) (dynamic: false, data: '0'.repeat((256 - bits) div 4) & x.dumpHex)
func encode[bits: static[int]](x: Stint[bits]): EncodeResult = func encode*[bits: static[int]](x: Stint[bits]): EncodeResult =
## Encodes a `Stint` to a textual representation for use in the JsonRPC ## Encodes a `Stint` to a textual representation for use in the JsonRPC
## `sendTransaction` call. ## `sendTransaction` call.
(dynamic: false, (dynamic: false,
@ -53,6 +53,13 @@ func encode[bits: static[int]](x: Stint[bits]): EncodeResult =
'0'.repeat((256 - bits) div 4) & x.dumpHex '0'.repeat((256 - bits) div 4) & x.dumpHex
) )
func decode*[bits: static[int]](input: string, to: type Stuint[bits]): Stuint[bits] =
fromHex(to, input)
func decode*[bits: static[int]](input: string, to: type Stint[bits]): Stint[bits] =
cast[Stint[bits]](fromHex(Stuint[bits], input))
macro makeTypeEnum(): untyped = macro makeTypeEnum(): untyped =
## This macro creates all the various types of Solidity contracts and maps ## This macro creates all the various types of Solidity contracts and maps
## them to the type used for their encoding. It also creates an enum to ## them to the type used for their encoding. It also creates an enum to
@ -85,6 +92,7 @@ macro makeTypeEnum(): untyped =
`identInt`* = Int256 `identInt`* = Int256
`identBool`* = distinct Int256 `identBool`* = distinct Int256
func encode*(x: `identBool`): EncodeResult = encode(Int256(x)) func encode*(x: `identBool`): EncodeResult = encode(Int256(x))
func decode*(input: string, x: `identBool`): `identBool` = `identBool`(decode(input, Stint[256]))
fields.add [ fields.add [
identAddress, identAddress,
identUint, identUint,
@ -117,6 +125,12 @@ macro makeTypeEnum(): untyped =
func encode*[N: static[int]](x: `identUfixed`[N]): EncodeResult = func encode*[N: static[int]](x: `identUfixed`[N]): EncodeResult =
encode(`identUint`(x) * (10 ^ N).to(`identUint`)) encode(`identUint`(x) * (10 ^ N).to(`identUint`))
func decode*[N: static[int]](input: string, to: `identFixed`[N]): `identFixed`[N] =
decode(input, `identInt`) div / (10 ^ N).to(`identInt`)
func decode*[N: static[int]](input: string, to: `identUfixed`[N]): `identFixed`[N] =
decode(input, `identUint`) div / (10 ^ N).to(`identUint`)
fields.add ident("Fixed" & $m) fields.add ident("Fixed" & $m)
fields.add ident("Ufixed" & $m) fields.add ident("Ufixed" & $m)
let let
@ -145,6 +159,8 @@ macro makeTypeEnum(): untyped =
func fromHex*(x: type `identBytes`, s: string): `identBytes` = func fromHex*(x: type `identBytes`, s: string): `identBytes` =
for i in 0..(`i`-1): for i in 0..(`i`-1):
`identResult`[i] = parseHexInt(s[i*2..i*2+1]).uint8 `identResult`[i] = parseHexInt(s[i*2..i*2+1]).uint8
func decode*(input: string, to: type `identBytes`): `identBytes` =
fromHex(to, input)
fields.add [ fields.add [
ident("Function"), ident("Function"),
@ -165,6 +181,8 @@ macro makeTypeEnum(): untyped =
`identResult`.data &= "00".repeat(32 - (x.len mod 32)) `identResult`.data &= "00".repeat(32 - (x.len mod 32))
func fromHex*(x: type `identBytes`, s: string): `identBytes` = func fromHex*(x: type `identBytes`, s: string): `identBytes` =
fromHex(s) fromHex(s)
func decode*(input: string, to: type `identBytes`): `identBytes` =
fromHex(to, input)
result.add newEnum(ident "FieldKind", fields, public = true, pure = true) result.add newEnum(ident "FieldKind", fields, public = true, pure = true)
echo result.repr echo result.repr
@ -175,7 +193,7 @@ type
Encodable = concept x Encodable = concept x
encode(x) is EncodeResult encode(x) is EncodeResult
func encode(x: seq[Encodable]): EncodeResult = func encode*(x: seq[Encodable]): EncodeResult =
result.dynamic = true result.dynamic = true
result.data = x.len.toHex(64).toLower result.data = x.len.toHex(64).toLower
var var
@ -191,7 +209,13 @@ func encode(x: seq[Encodable]): EncodeResult =
offset += encoded.data.len offset += encoded.data.len
result.data &= data result.data &= data
func encode(x: openArray[Encodable]): EncodeResult = func decode*[T](input: string, to: seq[T]): seq[T] =
var count = input[0..64].decode(Stuint)
result = newSeq[T](count)
for i in 0..count:
result[i] = input[i*64 .. (i+1)*64].decode(T)
func encode*(x: openArray[Encodable]): EncodeResult =
result.dynamic = false result.dynamic = false
result.data = "" result.data = ""
var var
@ -206,6 +230,11 @@ func encode(x: openArray[Encodable]): EncodeResult =
result.data &= encoded.data result.data &= encoded.data
offset += encoded.data.len offset += encoded.data.len
func decode*[T; I: static int](input: string, to: array[0..I, T]): array[0..I, T] =
for i in 0..I:
result[i] = input[i*64 .. (i+1)*64].decode(T)
type type
InterfaceObjectKind = enum InterfaceObjectKind = enum
function, constructor, event function, constructor, event
@ -282,11 +311,31 @@ proc getEventSignature(event: EventObject): string =
proc parseContract(body: NimNode): seq[InterfaceObject] = proc parseContract(body: NimNode): seq[InterfaceObject] =
proc parseOutputs(outputNode: NimNode): seq[FunctionInputOutput] = proc parseOutputs(outputNode: NimNode): seq[FunctionInputOutput] =
if outputNode.kind == nnkIdent: #if outputNode.kind == nnkIdent:
# result.add FunctionInputOutput(
# name: "",
# kind: parseEnum[FieldKind]($outputNode.ident)
# )
case outputNode.kind:
of nnkBracketExpr:
result.add FunctionInputOutput( result.add FunctionInputOutput(
name: "", name: "",
kind: parseEnum[FieldKind]($outputNode.ident) kind: parseEnum[FieldKind]($outputNode[0].ident),
sequenceKind: if outputNode.len == 1:
dynamic
else:
fixed
) )
if outputNode.len == 2:
result[^1].count = outputNode[1].intVal.int
of nnkIdent:
result.add FunctionInputOutput(
name: "",
kind: parseEnum[FieldKind]($outputNode.ident),
sequenceKind: single
)
else:
discard
proc parseInputs(inputNodes: NimNode): seq[FunctionInputOutput] = proc parseInputs(inputNodes: NimNode): seq[FunctionInputOutput] =
for i in 1..<inputNodes.len: for i in 1..<inputNodes.len:
let input = inputNodes[i] let input = inputNodes[i]
@ -436,7 +485,7 @@ macro contract*(cname: untyped, body: untyped): untyped =
ident "Address" ident "Address"
else: else:
if obj.functionObject.outputs.len != 1: if obj.functionObject.outputs.len != 1:
newEmptyNode() ident "void"#newEmptyNode()
else: else:
ident $obj.functionObject.outputs[0].kind ident $obj.functionObject.outputs[0].kind
var var
@ -499,16 +548,23 @@ macro contract*(cname: untyped, body: untyped): untyped =
) )
case obj.functionObject.stateMutability: case obj.functionObject.stateMutability:
of view: of view:
let cc = ident "cc"
procDef[6].add quote do: procDef[6].add quote do:
var cc: EthCall var `cc`: EthCall
cc.source = some(`senderName`.address) `cc`.source = some(`senderName`.address)
#cc.to = `senderName`.contract.Contract.address #cc.to = `senderName`.contract.Contract.address
cc.to = `senderName`.contract.address `cc`.to = `senderName`.contract.address
`encoder` `encoder`
cc.data = some("0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`) `cc`.data = some("0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`)
echo cc.data echo `cc`.data
let response = await `senderName`.contract.`client`.eth_call(cc, "latest") if output != ident "void":
return response procDef[6].add quote do:
let response = await `senderName`.contract.`client`.eth_call(`cc`, "latest")
echo response
return response[2..^1].decode(`output`)
else:
procDef[6].add quote do:
await `senderName`.contract.`client`.eth_call(`cc`, "latest")
else: else:
procDef[6].add quote do: procDef[6].add quote do:
var cc: EthSend var cc: EthSend