From 031652b7397e0c0f448f4a9cb8678695665b34ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Pie=C5=84kowski?= Date: Thu, 3 Aug 2023 16:59:00 +0200 Subject: [PATCH] Fix the decoding of unsigned transactions (#243) * Recover sender address only for signed transactions * Add a test case for decoding an unsigned transaction * Add a test case for an EIP-2930 transaction --- lib/eth/tx/eip1559.rb | 15 ++++++++++----- lib/eth/tx/eip2930.rb | 15 ++++++++++----- lib/eth/tx/legacy.rb | 2 -- spec/eth/tx_spec.rb | 28 ++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/eth/tx/eip1559.rb b/lib/eth/tx/eip1559.rb index a8800beb..a1ea1c19 100644 --- a/lib/eth/tx/eip1559.rb +++ b/lib/eth/tx/eip1559.rb @@ -186,11 +186,16 @@ def decode(hex) # last but not least, set the type. @type = TYPE_1559 - # recover sender address - v = Chain.to_v recovery_id, chain_id - public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id) - address = Util.public_key_to_address(public_key).to_s - @sender = Tx.sanitize_address address + unless recovery_id.nil? + # recover sender address + v = Chain.to_v recovery_id, chain_id + public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id) + address = Util.public_key_to_address(public_key).to_s + @sender = Tx.sanitize_address address + else + # keep the 'from' field blank + @sender = Tx.sanitize_address nil + end end # Creates an unsigned copy of a transaction payload. diff --git a/lib/eth/tx/eip2930.rb b/lib/eth/tx/eip2930.rb index eec8a8ac..60e857ab 100644 --- a/lib/eth/tx/eip2930.rb +++ b/lib/eth/tx/eip2930.rb @@ -181,11 +181,16 @@ def decode(hex) # last but not least, set the type. @type = TYPE_2930 - # recover sender address - v = Chain.to_v recovery_id, chain_id - public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id) - address = Util.public_key_to_address(public_key).to_s - @sender = Tx.sanitize_address address + unless recovery_id.nil? + # recover sender address + v = Chain.to_v recovery_id, chain_id + public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id) + address = Util.public_key_to_address(public_key).to_s + @sender = Tx.sanitize_address address + else + # keep the 'from' field blank + @sender = Tx.sanitize_address nil + end end # Creates an unsigned copy of a transaction payload. diff --git a/lib/eth/tx/legacy.rb b/lib/eth/tx/legacy.rb index 8ed9d64f..14b89023 100644 --- a/lib/eth/tx/legacy.rb +++ b/lib/eth/tx/legacy.rb @@ -154,13 +154,11 @@ def decode(hex) _set_signature(v, r, s) unless chain_id.nil? - # recover sender address public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v}", chain_id) address = Util.public_key_to_address(public_key).to_s @sender = Tx.sanitize_address address else - # keep the 'from' field blank @sender = Tx.sanitize_address nil end diff --git a/spec/eth/tx_spec.rb b/spec/eth/tx_spec.rb index 1383457b..745fd64a 100644 --- a/spec/eth/tx_spec.rb +++ b/spec/eth/tx_spec.rb @@ -122,4 +122,32 @@ expect(tx.chain_id).to eq 56 end end + + describe '.decode an unsigned transaction' do + context 'EIP-1559' do + it "keeps the 'from' field blank" do + raw = "0x02f0050584b2d05e00851010b872008303841494caedbd63fb25c3126bfe96c1af208e4688e9817e87f6a3d9c63df00080c0" + tx = Tx.decode raw + + expect(tx.signature_y_parity).to eq nil + expect(tx.signature_r).to eq 0 + expect(tx.signature_s).to eq 0 + + expect(tx.sender).to eq "" + end + end + + context 'EIP-2930' do + it "keeps the 'from' field blank" do + raw = "01eb050585037e11d6008303841494caedbd63fb25c3126bfe96c1af208e4688e9817e87f6a3d9c63df00080c0" + tx = Tx.decode raw + + expect(tx.signature_y_parity).to eq nil + expect(tx.signature_r).to eq 0 + expect(tx.signature_s).to eq 0 + + expect(tx.sender).to eq "" + end + end + end end