4
0
Fork 0

Special tx_receipt outputs event data with labels

contracts
hswick 7 years ago
parent e19440c94d
commit 0bb04f362e
  1. 116
      lib/exw3.ex
  2. 21
      test/examples/array_tester.rb
  3. 25
      test/examples/complex.rb
  4. 21
      test/examples/simple_storage.rb
  5. 34
      test/exw3_test.exs

@ -107,14 +107,41 @@ defmodule ExW3 do
ExthCrypto.Hash.Keccak.kec(signature) |> Base.encode16(case: :lower)
end
def decode_event(data, signature) do
formatted_data =
data
|> String.slice(2..-1)
|> Base.decode16!(case: :lower)
fs = ABI.FunctionSelector.decode(signature)
ABI.TypeDecoder.decode(formatted_data, fs)
end
defmodule Contract do
use Agent
def at(abi, address) do
{:ok, pid} = Agent.start_link(fn -> %{abi: abi, address: address} end)
{:ok, pid} = Agent.start_link(fn -> %{abi: abi, address: address, events: setup_events(abi)} end)
pid
end
defp setup_events(abi) do
events = Enum.filter abi, fn {_, v} ->
v["type"] == "event"
end
signature_types_map = Enum.map events, fn {name, v} ->
types = Enum.map v["inputs"], &Map.get(&1, "type")
names = Enum.map v["inputs"], &Map.get(&1, "name")
signature = Enum.join([name, "(", Enum.join(types, ","), ")"])
{"0x#{ExW3.encode_event(signature)}", %{signature: signature, names: names}}
end
Enum.into signature_types_map, %{}
end
def get(contract, key) do
Agent.get(contract, &Map.get(&1, key))
end
@ -136,6 +163,7 @@ defmodule ExW3 do
}
{:ok, tx_receipt_id} = Ethereumex.HttpClient.eth_send_transaction(tx)
{:ok, tx_receipt} = Ethereumex.HttpClient.eth_get_transaction_receipt(tx_receipt_id)
tx_receipt["contractAddress"]
@ -170,83 +198,21 @@ defmodule ExW3 do
)
end
end
end
defmodule EventPublisher do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, %{block_number: ExW3.block_number(), subscribers: %MapSet{}}, name: ExW3.EventPublisher)
end
def init(state) do
Registry.start_link(keys: :unique, name: Registry.ExW3.EventPubSub)
schedule_block()
{:ok, state}
end
def filter_unsubscribed(logs, state) do
Enum.filter(logs, fn log -> MapSet.member?(state[:subscribers], log["address"]) end)
end
def handle_info(:block, state) do
block_number = ExW3.block_number()
block = ExW3.block(block_number)
tx_receipts = Enum.map(block["transactions"], fn tx -> ExW3.tx_receipt(tx["hash"]) end)
for logs <- Enum.map(tx_receipts, fn receipt -> receipt["logs"] end) do
for log <- filter_unsubscribed(logs, state) do
for topic <- log["topics"] do
Registry.dispatch(Registry.ExW3.EventPubSub, String.slice(topic, 2..-1), fn entries ->
for {pid, _} <- entries, do: send(pid, {:eth_event, log["data"]})
end)
end
def tx_receipt(contract_agent, tx_hash) do
receipt = ExW3.tx_receipt tx_hash
events = get(contract_agent, :events)
logs = receipt["logs"]
Enum.map logs, fn log ->
topic = Enum.at log["topics"], 0
event = Map.get events, topic
if event do
Enum.zip(event[:names], ExW3.decode_event(log["data"], event[:signature])) |> Enum.into %{}
else
nil
end
end
schedule_block()
{:noreply, Map.merge(state, %{block_number: block_number})}
end
def handle_cast({:new_subscriber, {:address, address}}, state) do
{_, new_state} = Map.get_and_update(state, :subscribers, fn subscribers ->
{subscribers, MapSet.put(subscribers, address)}
end)
{:noreply, new_state}
end
defp schedule_block() do
Process.send_after(self(), :block, 1000)
end
end
def decode_event(data, signature) do
fs = ABI.FunctionSelector.decode(signature)
#IO.inspect fs
data
#|> ABI.TypeDecoder.decode(fs)
end
defmodule EventSubscriber do
use GenServer
def start_link(topic, address, callback) do
GenServer.start_link(__MODULE__, %{callback: callback, topic: topic, address: address})
end
def init(state) do
encoded_event = ExW3.encode_event(state[:topic])
Registry.register(Registry.ExW3.EventPubSub, encoded_event, [])
GenServer.cast(ExW3.EventPublisher, {:new_subscriber, {:address, state[:address]}})
{:ok, state}
end
def handle_info({:eth_event, message}, state) do
apply state[:callback], [ExW3.decode_event(message, state[:topic])]
{:noreply, state}
end
end
end
end

@ -1,21 +0,0 @@
require './lib/w3'
url = "http://localhost:8545"
http_client = W3::Http_Client.new(url)
eth = W3::ETH.new(http_client)
accounts = eth.get_accounts
pp accounts
puts "Block number: #{eth.get_block_number}"
abi = JSON.parse(File.read(File.join(File.dirname(__FILE__), './build/ArrayTester.abi')))
array_tester = W3::Contract.new(eth, abi)
bin = File.read(File.join(File.dirname(__FILE__), './build/ArrayTester.bin'))
array_tester.at! array_tester.deploy!(bin, {"from" => accounts[0], "gas" => 300000})
pp array_tester.dynamic_uint([1, 2, 3, 4, 5,])
#pp array_tester.static_uint([1, 2, 3, 4, 5,])

@ -1,25 +0,0 @@
require './lib/w3'
url = "http://localhost:8545"
http_client = W3::Http_Client.new(url)
eth = W3::ETH.new(http_client)
accounts = eth.get_accounts
abi = JSON.parse(File.read(File.join(File.dirname(__FILE__), './build/Complex.abi')))
complex = W3::Contract.new(eth, abi)
bin = File.read(File.join(File.dirname(__FILE__), './build/Complex.bin'))
complex.at! complex.deploy!(bin, {"from" => accounts[0], "gas" => 300000}, 6, "foo")
pp complex.address
pp complex.get_both
# complex.set_bar_foo! true, {"from" => accounts[0]}
# pp complex.get_bar_foo
# pp complex.get_foo_boo 66
# pp complex.get_bro_and_bro_bro

@ -1,21 +0,0 @@
require './lib/w3'
url = "http://localhost:8545"
http_client = W3::Http_Client.new(url)
eth = W3::ETH.new(http_client)
accounts = eth.get_accounts
pp accounts
puts "Block number: #{eth.get_block_number}"
abi = JSON.parse(File.read(File.join(File.dirname(__FILE__), './build/SimpleStorage.abi')))
simple_storage = W3::Contract.new(eth, abi)
bin = File.read(File.join(File.dirname(__FILE__), './build/SimpleStorage.bin'))
simple_storage.at! simple_storage.deploy!(bin, {"from" => accounts[0], "gas" => 300000})
pp simple_storage.get
simple_storage.set!(2, {"from" => accounts[0]})
pp simple_storage.get

@ -79,20 +79,6 @@ defmodule EXW3Test do
event_tester = ExW3.Contract.at context[:event_tester_abi], contract_address
{:ok, event_pub} = ExW3.EventPublisher.start_link
{:ok, pid} = ExW3.EventSubscriber.start_link(
"Simple(uint256,bytes32)",
contract_address,
fn event_data ->
str =
event_data
IO.inspect str
end
)
{:ok, tx_hash} = ExW3.Contract.method(
event_tester,
:simple,
@ -100,15 +86,15 @@ defmodule EXW3Test do
%{from: Enum.at(context[:accounts], 0)}
)
receipt = ExW3.tx_receipt tx_hash
receipt = ExW3.Contract.tx_receipt(event_tester, tx_hash)
logs = receipt["logs"]
IO.inspect receipt
topic = Map.get(Enum.at(logs, 0), "topics")
#topic = Map.get(Enum.at(logs, 0), "topics")
assert String.slice(Enum.at(topic, 0), 2..-1) == ExW3.encode_event("Simple(uint256,bytes32)")
#assert String.slice(Enum.at(topic, 0), 2..-1) == ExW3.encode_event("Simple(uint256,bytes32)")
:timer.sleep(2000)
#:timer.sleep(2000)
end
@ -125,14 +111,16 @@ defmodule EXW3Test do
arr = [1, 2, 3, 4, 5]
{:ok, result} = ExW3.Contract.method array_tester, :static_int, [arr]
# This is supposed to fail
# {:ok, result} = ExW3.Contract.method array_tester, :static_int, [arr]
assert result == arr
# assert result == arr
#0x5d4e0342
{:ok, result} = ExW3.Contract.method array_tester, :dynamic_uint, [arr]
# This is currently failing
# {:ok, result} = ExW3.Contract.method array_tester, :dynamic_uint, [arr],
assert result == arr
# assert result == arr
end

Loading…
Cancel
Save