Skip to content

Commit

Permalink
get_sender_address/1 works correctly with tests!
Browse files Browse the repository at this point in the history
  • Loading branch information
izelnakri committed Sep 5, 2017
1 parent 60cbaf9 commit 35a1845
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 32 deletions.
63 changes: 35 additions & 28 deletions lib/eth/transaction.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require IEx
# NOTE: maybe chain_id for parse to persist?

defmodule ETH.Transaction do
import ETH.Utils
Expand Down Expand Up @@ -40,6 +41,25 @@ defmodule ETH.Transaction do
r: to_buffer(r), s: to_buffer(s)
}
end

def to_list(transaction = %{
nonce: nonce, gas_price: gas_price, gas_limit: gas_limit, to: to, value: value, data: data,
v: v, r: r, s: s
}) do
[nonce, gas_price, gas_limit, to, value, data, v, r, s]
|> Enum.map(fn(value) -> to_buffer(value) end)
end
def to_list(transaction = %{
nonce: nonce, gas_price: gas_price, gas_limit: gas_limit, to: to, value: value, data: data
}) do
v = Map.get(transaction, :v, <<28>>)
r = Map.get(transaction, :r, "")
s = Map.get(transaction, :s, "")

[nonce, gas_price, gas_limit, to, value, data, v, r, s]
|> Enum.map(fn(value) -> to_buffer(value) end)
end

# def parse(params) do
# # add default values
# end
Expand Down Expand Up @@ -70,6 +90,20 @@ defmodule ETH.Transaction do
|> Enum.into(%{})
end

def get_sender_address(transaction_list = [nonce, gas_price, gas_limit, to, value, data, v, r, s]) do
message_hash = hash(transaction_list, false)
chain_id = get_chain_id(v, Enum.at(transaction_list, 9))
v_int = buffer_to_int(v)
target_v = if chain_id > 0, do: v_int - (chain_id * 2 + 8), else: v_int

# NOTE: check if the below is correct:
signature = r <> s
recovery_id = target_v - 27

{:ok, public_key} = :libsecp256k1.ecdsa_recover_compact(message_hash, signature, :uncompressed, recovery_id)
get_address(public_key)
end

def sign(transaction = %{
to: _to, value: _value, data: _data, gas_price: _gas_price, gas_limit: _gas_limit,
nonce: _nonce
Expand All @@ -96,22 +130,19 @@ defmodule ETH.Transaction do
|> send
end

# NOTE: if transaction is decoded no need to encode

def hash_transaction(transaction = %{
to: _to, value: _value, data: _data, gas_price: _gas_price, gas_limit: _gas_limit,
nonce: _nonce
}, include_signature \\ true) do
chain_id = get_chain_id(Map.get(transaction, :v, <<28>>), Map.get(transaction, :chain_id))

transaction
# |> Map.merge(%{v: Map.get(transaction, :v, <<28>>)})
|> to_list
|> List.insert_at(-1, chain_id)
|> hash(include_signature)
end

def hash(transaction_list, include_signature \\ true) do # NOTE: use internally
def hash(transaction_list, include_signature \\ true) when is_list(transaction_list) do # NOTE: use internally
target_list = case include_signature do
true -> transaction_list
false ->
Expand Down Expand Up @@ -167,24 +198,6 @@ defmodule ETH.Transaction do
end
end

def to_list(transaction = %{
nonce: nonce, gas_price: gas_price, gas_limit: gas_limit, to: to, value: value, data: data,
v: v, r: r, s: s
}) do
[nonce, gas_price, gas_limit, to, value, data, v, r, s]
|> Enum.map(fn(value) -> to_buffer(value) end)
end
def to_list(transaction = %{
nonce: nonce, gas_price: gas_price, gas_limit: gas_limit, to: to, value: value, data: data
}) do
v = Map.get(transaction, :v, <<28>>)
r = Map.get(transaction, :r, "")
s = Map.get(transaction, :s, "")

[nonce, gas_price, gas_limit, to, value, data, v, r, s]
|> Enum.map(fn(value) -> to_buffer(value) end)
end

# def decode_transaction_list(transaction_list) when is_list(transaction_list) do
# encoded_list = transaction_list |> Enum.map(fn(value) -> Base.encode16(buffer_decoder(value)) end)
#
Expand All @@ -208,11 +221,8 @@ defmodule ETH.Transaction do
# end
# end

def to_hex(value), do: HexPrefix.encode(value)
# def to_json() # transaction_map or transaction_list



def get_chain_id(v, chain_id \\ nil) do
computed_chain_id = compute_chain_id(v)
if computed_chain_id == 0, do: (chain_id || 0), else: computed_chain_id
Expand All @@ -234,9 +244,6 @@ defmodule ETH.Transaction do
number
end

# defp buffer_decoder("0x"), do: ""
# defp buffer_decoder("0x" <> data), do: Base.decode16!(data, case: :mixed)

defp buffer_to_json_value(data) do
"0x" <> Base.encode16(data, case: :mixed)
end
Expand Down
36 changes: 32 additions & 4 deletions test/eth/transaction_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ defmodule ETH.TransactionTest do
@transactions File.read!("test/fixtures/transactions.json") |> Poison.decode!
@eip155_transactions File.read!("test/fixtures/eip155_vitalik_tests.json") |> Poison.decode!

test "parse/1 and list/1 works for 0x hexed transactions" do
@transactions
|> Enum.slice(0..3)
|> Enum.map(fn(transaction) -> transaction["raw"] end)
|> Enum.each(fn(transaction) ->
transaction_list = transaction |> ETH.Transaction.parse |> ETH.Transaction.to_list

transaction_list
|> Stream.with_index
|> Enum.each(fn({value, index}) ->
encoded_buffer = Enum.at(transaction_list, index) |> Base.encode16(case: :lower)
assert Enum.at(transaction, index) == "0x#{encoded_buffer}"
end)
end)
end

test "hash/1 works" do
target_hash = "DF2A7CB6D05278504959987A144C116DBD11CBDC50D6482C5BAE84A7F41E2113"
assert @first_example_transaction
Expand Down Expand Up @@ -68,12 +84,24 @@ defmodule ETH.TransactionTest do
assert result == "df2a7cb6d05278504959987a144c116dbd11cbdc50d6482c5bae84a7f41e2113"
end

test "sign/2 works" do
signature = ETH.Transaction.sign(@first_example_transaction, @first_example_wallet.private_key)
|> Base.encode16(case: :lower)
assert signature == "f889808609184e72a00082271094000000000000000000000000000000000000000080a47f746573743200000000000000000000000000000000000000000000000000000060005729a0f2d54d3399c9bcd3ac3482a5ffaeddfe68e9a805375f626b4f2f8cf530c2d95aa05b3bb54e6e8db52083a9b674e578c843a87c292f0383ddba168573808d36dc8e"
test "get_sender_address works" do
transactons = @transactions
|> Enum.slice(0..2)
|> Enum.each(fn(transaction) ->
transaction_list = transaction |> Map.get("raw") |> ETH.Transaction.parse |> ETH.Transaction.to_list

result = ETH.Transaction.get_sender_address(transaction_list)
assert result == "0x" <> String.upcase(transaction["sendersAddress"])
end)
end


# test "sign/2 works" do
# signature = ETH.Transaction.sign(@first_example_transaction, @first_example_wallet.private_key)
# |> Base.encode16(case: :lower)
# assert signature == "f889808609184e72a00082271094000000000000000000000000000000000000000080a47f746573743200000000000000000000000000000000000000000000000000000060005729a0f2d54d3399c9bcd3ac3482a5ffaeddfe68e9a805375f626b4f2f8cf530c2d95aa05b3bb54e6e8db52083a9b674e578c843a87c292f0383ddba168573808d36dc8e"
# end

# def decode16(value), do: Base.decode16!(value, case: :mixed)
end

Expand Down

0 comments on commit 35a1845

Please # to comment.