q9f / eth.rb

a straightforward library to build, sign, and broadcast ethereum transactions anywhere you can run ruby.
https://q9f.github.io/eth.rb
Apache License 2.0
204 stars 88 forks source link

Using (Polygon) Mumbai Testnet Chain Id 80001 forces error 'Invalid signature v byte 27 for chain ID 80001!' #124

Closed Wertster closed 2 years ago

Wertster commented 2 years ago

Hoping this is the correct manner in which to raise queries? I'm using ruby-eth (0.5.4 looking at my gemfile.lock) to verify metamask signatures (personal sign'ed). My implementation has been stable/fine with default Chain ID (1), but now I am looking to bind to Chain Id 8001. Testing this has driven errors 'Invalid signature v byte 27 for chain ID 80001!'.

The function I call is Eth::Signature::personal_recover - passing in Chain_id 80001

    def personal_recover(message, signature, chain_id = Chain::ETHEREUM)
      prefixed_message = prefix_message message
      hashed_message = Util.keccak256 prefixed_message
      recover hashed_message, signature, chain_id
    end

As this delegates to the Eth::Signature::recover function the dissect function is called and in tracing that I see the 'v' value is 27.

  def recover(blob, signature, chain_id = Chain::ETHEREUM)
      context = Secp256k1::Context.new
      r, s, v = dissect signature
      v = v.to_i(16)
      raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < chain_id
      recovery_id = Chain.to_recovery_id v, chain_id
      signature_rs = Util.hex_to_bin "#{r}#{s}"
      recoverable_signature = context.recoverable_signature_from_compact signature_rs, recovery_id
      public_key = recoverable_signature.recover_public_key blob
      Util.bin_to_hex public_key.uncompressed
    end

The error I am receiving seems to be a very simple logic trap, in which the SignatureError is raised if v (27) is less than the chain_id (80001).

If this is the case, how can i use a chain with an id more than 27? Apologies if i may be missing something contextual here (i.e. some implied blockchain convention), but looking purely at the execution path in my code, and into this gem, i can only see my issue being 27 < 80001.

Is this an intended constraint within the gem logic?

Wertster commented 2 years ago

https://github.com/q9f/eth.rb/blob/main/lib/eth/signature.rb

Wertster commented 2 years ago

Inputs to this recover function : blob (signature) cceb4a6992bd6db76bf95f4408ab5266264234fd727204d926ac01d8fb5c124e1842964ddb622537689cb087a01080a507ff0ebbe9931302c95e1f84bb02fb2b1b length is 130 r = cceb4a6992bd6db76bf95f4408ab5266264234fd727204d926ac01d8fb5c124e s = 1842964ddb622537689cb087a01080a507ff0ebbe9931302c95e1f84bb02fb2b v = 1b v.to_i(16) = 27 chain_id = 80001

raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < chain_id

Wertster commented 2 years ago

Please forgive me, I've been workign this most of the day and realise i have made a mistake - not injecting the custom (non default chain_id 80001 into the Eth::Signature.personal_recover method. I am now unblocked - there is no logic constraint within the code. Thankyou and apologies for any wasted thinking time !