8000 Dynamic struct encoding by peter-chung-xfers · Pull Request #135 · q9f/eth.rb · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

< 8000 bdi class="js-issue-title markdown-title">Dynamic struct encoding #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from

Conversation

peter-chung-xfers
Copy link
Contributor
@peter-chung-xfers peter-chung-xfers commented Jul 10, 2022

adding abi encoder for the following data types

  • dynamic struct
  • static struct
  • dynamic array of dynamic struct
  • dynamic array of static struct
  • static array of dynamic struct
  • static array of static struct

@codecov-commenter
Copy link
codecov-commenter commented Jul 10, 2022

Codecov Report

Merging #135 (1699cac) into main (6e1a491) will decrease coverage by 18.54%.
The diff coverage is 24.50%.

❗ Current head 1699cac differs from pull request most recent head c567dc1. Consider uploading reports for the commit c567dc1 to get more accurate results

@@             Coverage Diff             @@
##             main     #135       +/-   ##
===========================================
- Coverage   99.74%   81.20%   -18.55%     
===========================================
  Files          67       67               
  Lines        3899     4059      +160     
===========================================
- Hits         3889     3296      -593     
- Misses         10      763      +753     
Impacted Files Coverage Δ
lib/eth/client.rb 55.00% <0.00%> (-45.00%) ⬇️
lib/eth/contract/function.rb 75.00% <0.00%> (-25.00%) ⬇️
lib/eth/abi.rb 15.55% <7.14%> (-84.45%) ⬇️
spec/eth/contract_spec.rb 53.33% <13.33%> (-46.67%) ⬇️
spec/eth/abi/type_spec.rb 45.23% <17.64%> (-54.77%) ⬇️
lib/eth/abi/type.rb 72.22% <36.36%> (-27.78%) ⬇️
spec/eth/abi_spec.rb 34.50% <50.00%> (-65.50%) ⬇️
lib/eth/contract/function_input.rb 72.72% <66.66%> (-27.28%) ⬇️
spec/eth/contract/function_spec.rb 57.50% <85.71%> (-42.50%) ⬇️
... and 29 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@peter-chung-xfers
Copy link
Contributor Author

hey @q9f could you help me review this please

Copy link
Owner
@q9f q9f left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much, this is very well done!

I only left two minor comments.

@@ -98,15 +109,13 @@ def ==(another_type)
def size
s = nil
if dimensions.empty?
unless ["string", "bytes"].include?(base_type) and sub_type.empty?
if !(["string", "bytes", "tuple"].include?(base_type) and sub_type.empty?)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: any reason you changed unless to !if?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. https://stackoverflow.com/a/19216609
  2. https://stackoverflow.com/questions/41196492/ruby-unless-bug-with-multiple-conditions
  3. https://signalvnoise.com/posts/2699-making-sense-with-rubys-unless
  4. The and keyword having lower operator precedence than && definitely didn't help with the readability

Some good rules of thumb:

  1. Prefer if over unless 90% of the time.
  2. Prefer if over unless 100% of the time if there are multiple conditions.
  3. Never use and or or or not.

@@ -138,6 +161,7 @@ def validate_base_type(base_type, sub_type)

# bytes can be no longer than 32 bytes
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? || sub_type.to_i <= 32
when "tuple"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any idea how to validate this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:

raise ParseError if (sub_type.dimensions.size != 1 || sub_type.dimensions.first&.zero?) && !sub_type.is_dynamic?

Just taking a stab at it

@q9f q9f added the enhancement New feature or request label Sep 26, 2022
elsif type.is_dynamic?
raise EncodingError, "Argument must be an Array" unless arg.instance_of? Array

elsif type.base_type == "tuple" && type.dimensions.size == 1 && type.dimensions[0] != 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If type.dimensions[0] is nil, this would evaluate to true. Just wanted to make sure that was ok.

# encodes dynamic-sized arrays
head, tail = "", ""
head += encode_type Type.size_type, arg.size
head += encode_type(Type.size_type, arg.size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on the style change

@@ -123,6 +134,22 @@ def encode_type(type, arg)
end
end

def encode_struct_offsets(type, arg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add documentation here? I can't tell what this method is doing :(

I don't understand why there's so much class-level code, rather than using OOP and letting Ruby shine. But I guess that's a question for @q9f ❤️ ❤️

I would love to help get an idiomatic Ruby version of this library ready for a 1.0.0 release

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is almost as old as Ruby, I haven't written it. I rewrote everything except for the ABI parser and RLP encoder. Are you volunteering? :)

@q9f
Copy link
Owner
q9f commented Oct 27, 2022

I'll be accepting this as is and resolve your comments on a new branch @mculp (I don't have write access here.)

@peter-chung-xfers
Copy link
Contributor Author

@q9f @mculp

I don't really have time for this right now please take over thanks

peter-chung-xfers and others added 13 commits October 28, 2022 02:37
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
Co-authored-by: Matt Culpepper <mculp@users.noreply.github.com>
@@ -73,6 +83,8 @@ def parse(type)
@base_type = base_type
@sub_type = sub_type
@dimensions = dims.map { |x| x[1...-1].to_i }
@components = components.map { |component| Eth::Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } if components.any?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

components.any? might fail if components = nil

raise EncodingError, "Expecting #{type.components.size} elements: #{arg}" unless arg.size == type.components.size

static_size = 0
type.components.each do |component|

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be type.components.each_with_index do |component, i|

component_type = type.components[i]
if component_type.is_dynamic?
offsets_and_static_values << encode_type(Type.size_type, dynamic_offset)
dynamic_value << encode_type(component_type, arg.is_a?(Array) ? arg[i] : arg[component_type.name])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be dynamic_values

@q9f
Copy link
Owner
q9f commented Dec 21, 2022

Thank you @unbanksy - your comments were spot on.

I cannot edit this branch, so I took over in >> #185

@q9f q9f closed this Dec 21, 2022
q9f added a commit that referenced this pull request Dec 21, 2022
* add test case

* eth/abi: support dynamic struct encoding

* remove unused function

* typo

* uncomment spec

* cleanup spec

* test tuple2

* add tuple2.sol

* Update lib/eth/contract/function_input.rb

* Update lib/eth/client.rb

* Update lib/eth/contract/function.rb

* Update lib/eth/abi/type.rb

* Update lib/eth/abi.rb

* Update lib/eth/abi.rb

* Update lib/eth/abi/type.rb

* Update lib/eth/abi/type.rb

* Update lib/eth/abi/type.rb

* Update lib/eth/abi.rb

* Update lib/eth/abi.rb

* Update lib/eth/abi.rb

* Update lib/eth/abi/type.rb

* eth/abi: fix tests for dynamic struct encoding

* eth/abi: fix documentation and formatting

Co-authored-by: Peter Chung <peter.chung@fazzfinancial.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0