se3000 / ruby-eth

Gem for creating and signing Ethereum transactions.
MIT License
265 stars 98 forks source link

Breaking changes with openssl 1.1+: FFI::NotFoundError: Function 'SSL_library_init' not found in [libssl.so] #9

Closed 5chdn closed 7 years ago

5chdn commented 7 years ago

I can't create a transaction with ethereum.rb and ruby-eth and it breaks down to some Eth::OpenSsl issue. Here is my irb sandbox, nulled all sensitive data:

irb(main):001:0> require 'eth'
=> true

irb(main):002:0> key = Eth::Key.decrypt File.read('path/to/some/UTC-file.json'), 'password'
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
=> #<Eth::Key:0x00000000 @private_key=#<MoneyTree::PrivateKey:0x00000000 @options={:key=>"000...000"}, @ec_key=#<OpenSSL::PKey::EC:0x00000000>, @raw_key="000...000", @key="000...000">, @public_key=#<MoneyTree::PublicKey:0x00000000 @options={:compressed=>false}, @private_key=#<MoneyTree::PrivateKey:0x00000000 @options={:key=>"000...000"}, @ec_key=#<OpenSSL::PKey::EC:0x00000000>, @raw_key="000...000", @key="000...000">, @point=#<OpenSSL::PKey::EC::Point:0x00000000 @group=#<OpenSSL::PKey::EC::Group:0x00000000>>, @group=#<OpenSSL::PKey::EC::Group:0x00000000>, @raw_key="000...000", @key="000...000">>

irb(main):008:0> require 'ethereum.rb'
=> true

irb(main):009:0> parity = Ethereum::IpcClient.new '/home/user/.local/share/io.parity.ethereum/jsonrpc.ipc', false
=> #<Ethereum::IpcClient:0x00000000 @id=0, @log=false, @batch=nil, @formatter=#<Ethereum::Formatter:0x00000000>, @gas_price=22000000000, @gas_limit=4000000, @ipcpath="/home/user/.local/share/io.parity.ethereum/jsonrpc.ipc">
irb(main):010:0> parity.transfer(key, '0x000...000', 1)
FFI::NotFoundError: Function 'SSL_library_init' not found in [libssl.so]
  from /home/user/.gem/ruby/2.4.0/gems/ffi-1.9.18/lib/ffi/library.rb:275:in `attach_function'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/open_ssl.rb:18:in `<class:OpenSsl>'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/open_ssl.rb:5:in `<module:Eth>'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/open_ssl.rb:4:in `<top (required)>'
  from /usr/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
  from /usr/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:48:in `block in sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `loop'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:43:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from (irb):10
  from /usr/bin/irb:11:in `<main>'

irb(main):011:0> parity.transfer_and_wait(key, '0x000...000', 1)
NoMethodError: undefined method `sign_compact' for Eth::OpenSsl:Class
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:48:in `block in sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `loop'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:43:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:106:in `transfer_and_wait'
  from (irb):11
  from /usr/bin/irb:11:in `<main>'

irb(main):012:0> parity.transfer key, '0x000...000', 1e18
RLP::Error::ObjectSerializationError: Serialization failed because of field value ('Can only serialize integers')
  from /home/user/.gem/ruby/2.4.0/gems/rlp-0.7.3/lib/rlp/sedes/serializable.rb:66:in `rescue in serialize'
  from /home/user/.gem/ruby/2.4.0/gems/rlp-0.7.3/lib/rlp/sedes/serializable.rb:63:in `serialize'
  from /home/user/.gem/ruby/2.4.0/gems/rlp-0.7.3/lib/rlp/encode.rb:49:in `encode'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:40:in `unsigned_encoded'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from (irb):12
  from /usr/bin/irb:11:in `<main>'

irb(main):013:0> parity.transfer key, '0x000...000', 100
NoMethodError: undefined method `sign_compact' for Eth::OpenSsl:Class
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:48:in `block in sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `loop'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:43:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from (irb):13
  from /usr/bin/irb:11:in `<main>'

irb(main):014:0> parity.transfer_and_wait key, '0x000...000', 1
NoMethodError: undefined method `sign_compact' for Eth::OpenSsl:Class
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:48:in `block in sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `loop'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:43:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:106:in `transfer_and_wait'
  from (irb):14
  from /usr/bin/irb:11:in `<main>'

irb(main):016:0> parity.transfer_and_wait key, '0x000...000', 1
NoMethodError: undefined method `sign_compact' for Eth::OpenSsl:Class
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:48:in `block in sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `loop'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:47:in `sign_hash'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/key.rb:43:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/eth-0.4.3/lib/eth/tx.rb:56:in `sign'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:101:in `transfer'
  from /home/user/.gem/ruby/2.4.0/gems/ethereum.rb-2.1.6/lib/ethereum/client.rb:106:in `transfer_and_wait'
  from (irb):16
  from /usr/bin/irb:11:in `<main>'

Not sure, is it an ruby-eth bug or am I missing something?

 user@host ~ $ uname -a
Linux host 4.10.13-1-ARCH #1 SMP PREEMPT Thu Apr 27 12:15:09 CEST 2017 x86_64 GNU/Linux
 user@host ~ $ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
 user@host ~ $ gem list --local
activesupport (5.0.2)
addressable (2.5.1)
bigdecimal (default: 1.3.0)
builder (3.2.3)
colorize (0.8.1)
concurrent-ruby (1.0.5)
did_you_mean (1.1.0)
digest-sha3 (1.1.0)
eth (0.4.3)
ethereum.rb (2.1.6)
faraday (0.12.0.1, 0.11.0)
faraday-http-cache (2.0.0)
faraday_middleware (0.11.0.1)
feedjira (2.1.2)
ffi (1.9.18)
i18n (0.8.1)
io-console (default: 0.4.6)
json (default: 2.0.2)
jwt (1.5.6)
loofah (2.0.3)
mini_portile2 (2.1.0)
minitest (5.10.1)
money-tree (0.9.0)
multi_json (1.12.1)
multipart-post (2.0.0)
net-telnet (0.1.1)
nokogiri (1.7.1)
octokit (4.7.0)
openssl (default: 2.0.3)
power_assert (0.4.1)
psych (default: 2.2.2)
public_suffix (2.0.5)
rake (12.0.0)
rdoc (default: 5.0.0)
rlp (0.7.3)
sawyer (0.8.1)
sax-machine (1.3.2)
test-unit (3.2.3)
thread_safe (0.3.6)
twilio-ruby (4.13.0)
tzinfo (1.2.3)
xmlrpc (0.2.1)
5chdn commented 7 years ago

Tests reveal the same applies for recover_compact.

ruby-eth $ rspec 

Eth::Address
  #valid?
    given an address with a valid checksum
      returns true
    given an address with an invalid checksum
      returns false
    given an address with all uppercase letters
      returns true
    given an address with all lowercase letters
      returns true
    given an invalid address
      returns true
  #checksummed
    follows EIP55 standard
    given an invalid address
      raises an error

EIP 155 and replay protection
  EIP155 example
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    decodes the transaction and recognizes the signer (FAILED - 1)
  pre-EIP155 fork
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    decodes the transaction and recognizes the signer (FAILED - 2)
  verifying a post-EIP155 signature with pre-EIP155 configuration
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    cannot verify the signature (FAILED - 3)
  verifying a pre-EIP155 signature with a post-EIP155 configuration
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    can verify the signature (FAILED - 4)

Eth
  .configure
    defaults to nil
    allows you to configure the chain ID
  #v_base
    is set to 27 by default
    calculates it off of the chain ID
  #replayable_v?
    returns true for anything other than 27 and 28
  #prevent_replays?
    when configured to the defaults
      should equal false
    when configured to a new chain
      should equal true
    when configured to the replayable chain
      should equal true

Eth::Key::Decrypter
  .perform
    recovers the examle key

Eth::Key::Encrypter
  .perform
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    recovers the key
    when specifying not to include the address
      recovers the key

Eth::Key
  #initialize
    returns a key with a new private key
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    regenerates an old private key
  #sign
    signs a message so that the public key is recoverable (FAILED - 5)
    when the network ID has been changed
      signs a message so that the public key is recoverable (FAILED - 6)
  #verify_signature
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    signs a message so that the public key is recoverable (FAILED - 7)
    when the signature matches another public key
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
      does not verify the signature (FAILED - 8)
    when the signature does not match any public key
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
      signs a message so that the public key is recoverable (FAILED - 9)
    when the network ID has been changed
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
      can verify signatures from the new network (FAILED - 10)
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
      can verify replayable signatures (FAILED - 11)
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
      cannot verify signatures from other non replayable networks (FAILED - 12)
  #address
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    should eq "0x759b427456623a33030bbC2195439C22A8a51d25"
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    should eq "0x759b427456623a33030bbC2195439C22A8a51d25"
  .encrypt/.decrypt
/home/user/.gem/ruby/2.4.0/gems/money-tree-0.9.0/lib/money-tree/key.rb:73: warning: constant ::Bignum is deprecated
    reads and writes keys in the Ethereum Secret Storage definition

Eth::Tx
  #initialize
    sets the arguments in the order of serializable fields
    when the gas limit is too low
      raises an InvalidTransaction error
    there are values beyond the unsigned integer max
      raises an InvalidTransaction error
    when configured to take data as binary
      still propperly sets the data field
  .decode
    returns an instance that matches the original enocded one (FAILED - 13)
    also accepts hex (FAILED - 14)
  #sign
    creates a recoverable signature for the transaction (FAILED - 15)
  #to_h
    returns all the same values (FAILED - 16)
    does not set the binary data field (FAILED - 17)
    can be converted back into a transaction (FAILED - 18)
  #hex
    creates a hex representation
  #from
    when the signature is present
      example at ./spec/eth/tx_spec.rb:149 (FAILED - 19)
    when the signature does NOT match
      example at ./spec/eth/tx_spec.rb:159 (FAILED - 20)
    when the signature is NOT present
      should be nil
  #hash
    hashes the serialized full transaction
  #data_hex
    converts the hex to binary and persists it
  #data_bin
    returns the data in a binary format
  #data
    when configured to use hex
      accepts hex
    when configured to use binary
      converts the hex to binary and persists it

Eth::Utils
  .int_to_base256
    gets the same result back
  .base256_to_int
    properly converts binary to integers
  .prefix_hex
    ensures that a hex value has 0x at the beginning
    does not reformat the hex or remove leading zeros
  .public_key_to_addres
    turns a hex public key into a hex address
  .keccak256
    properly hashes using
  .keccak256_rlp
    properly serializes and hashes
  .hex_to_bin
    raises an error when given invalid hex
  .ripemd160
    properly hashes with RIPEMD-160
  .format_address
    returns checksummed addresses

Ethereum common tests
  passes all the transaction tests (FAILED - 21)

Failures:

  1) EIP 155 and replay protection EIP155 example decodes the transaction and recognizes the signer
     Failure/Error: attach_function :SSL_library_init, [], :int

     FFI::NotFoundError:
       Function 'SSL_library_init' not found in [libssl.so]
     # /home/user/.gem/ruby/2.4.0/gems/ffi-1.9.18/lib/ffi/library.rb:275:in `attach_function'
     # ./lib/eth/open_ssl.rb:18:in `<class:OpenSsl>'
     # ./lib/eth/open_ssl.rb:5:in `<module:Eth>'
     # ./lib/eth/open_ssl.rb:4:in `<top (required)>'
     # ./lib/eth/key.rb:55:in `verify_signature'
     # ./spec/eth/eip155_spec.rb:20:in `block (3 levels) in <top (required)>'

  2) EIP 155 and replay protection pre-EIP155 fork decodes the transaction and recognizes the signer
     Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

     NoMethodError:
       undefined method `sign_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:48:in `block in sign_hash'
     # ./lib/eth/key.rb:47:in `loop'
     # ./lib/eth/key.rb:47:in `sign_hash'
     # ./lib/eth/key.rb:43:in `sign'
     # ./lib/eth/tx.rb:56:in `sign'
     # ./spec/eth/eip155_spec.rb:34:in `block (3 levels) in <top (required)>'
     # ./spec/eth/eip155_spec.rb:37:in `block (3 levels) in <top (required)>'
     # ./spec/eth/eip155_spec.rb:40:in `block (3 levels) in <top (required)>'

  3) EIP 155 and replay protection verifying a post-EIP155 signature with pre-EIP155 configuration cannot verify the signature
     Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

     NoMethodError:
       undefined method `sign_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:48:in `block in sign_hash'
     # ./lib/eth/key.rb:47:in `loop'
     # ./lib/eth/key.rb:47:in `sign_hash'
     # ./lib/eth/key.rb:43:in `sign'
     # ./lib/eth/tx.rb:56:in `sign'
     # ./spec/eth/eip155_spec.rb:64:in `block (3 levels) in <top (required)>'

  4) EIP 155 and replay protection verifying a pre-EIP155 signature with a post-EIP155 configuration can verify the signature
     Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

     NoMethodError:
       undefined method `sign_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:48:in `block in sign_hash'
     # ./lib/eth/key.rb:47:in `loop'
     # ./lib/eth/key.rb:47:in `sign_hash'
     # ./lib/eth/key.rb:43:in `sign'
     # ./lib/eth/tx.rb:56:in `sign'
     # ./spec/eth/eip155_spec.rb:85:in `block (3 levels) in <top (required)>'

  5) Eth::Key#sign signs a message so that the public key is recoverable
     Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

     NoMethodError:
       undefined method `sign_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:48:in `block in sign_hash'
     # ./lib/eth/key.rb:47:in `loop'
     # ./lib/eth/key.rb:47:in `sign_hash'
     # ./lib/eth/key.rb:43:in `sign'
     # ./spec/eth/key_spec.rb:28:in `block (4 levels) in <top (required)>'
     # ./spec/eth/key_spec.rb:27:in `times'
     # ./spec/eth/key_spec.rb:27:in `block (3 levels) in <top (required)>'

  6) Eth::Key#sign when the network ID has been changed signs a message so that the public key is recoverable
     Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

     NoMethodError:
       undefined method `sign_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:48:in `block in sign_hash'
     # ./lib/eth/key.rb:47:in `loop'
     # ./lib/eth/key.rb:47:in `sign_hash'
     # ./lib/eth/key.rb:43:in `sign'
     # ./spec/eth/key_spec.rb:41:in `block (5 levels) in <top (required)>'
     # ./spec/eth/key_spec.rb:40:in `times'
     # ./spec/eth/key_spec.rb:40:in `block (4 levels) in <top (required)>'

  7) Eth::Key#verify_signature signs a message so that the public key is recoverable
     Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

     NoMethodError:
       undefined method `recover_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:55:in `verify_signature'
     # ./spec/eth/key_spec.rb:57:in `block (3 levels) in <top (required)>'

  8) Eth::Key#verify_signature when the signature matches another public key does not verify the signature
     Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

     NoMethodError:
       undefined method `recover_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:55:in `verify_signature'
     # ./spec/eth/key_spec.rb:65:in `block (4 levels) in <top (required)>'

  9) Eth::Key#verify_signature when the signature does not match any public key signs a message so that the public key is recoverable
     Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

     NoMethodError:
       undefined method `recover_compact' for Eth::OpenSsl:Class
     # ./lib/eth/key.rb:55:in `verify_signature'
     # ./spec/eth/key_spec.rb:73:in `block (4 levels) in <top (required)>'

  10) Eth::Key#verify_signature when the network ID has been changed can verify signatures from the new network
      Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

      NoMethodError:
        undefined method `recover_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:55:in `verify_signature'
      # ./spec/eth/key_spec.rb:83:in `block (4 levels) in <top (required)>'

  11) Eth::Key#verify_signature when the network ID has been changed can verify replayable signatures
      Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

      NoMethodError:
        undefined method `recover_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:55:in `verify_signature'
      # ./spec/eth/key_spec.rb:89:in `block (4 levels) in <top (required)>'

  12) Eth::Key#verify_signature when the network ID has been changed cannot verify signatures from other non replayable networks
      Failure/Error: public_hex == OpenSsl.recover_compact(hash, signature)

      NoMethodError:
        undefined method `recover_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:55:in `verify_signature'
      # ./spec/eth/key_spec.rb:95:in `block (4 levels) in <top (required)>'

  13) Eth::Tx.decode returns an instance that matches the original enocded one
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:67:in `block (3 levels) in <top (required)>'
      # ./spec/eth/tx_spec.rb:70:in `block (3 levels) in <top (required)>'

  14) Eth::Tx.decode also accepts hex
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:67:in `block (3 levels) in <top (required)>'
      # ./spec/eth/tx_spec.rb:75:in `block (3 levels) in <top (required)>'

  15) Eth::Tx#sign creates a recoverable signature for the transaction
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:87:in `block (3 levels) in <top (required)>'

  16) Eth::Tx#to_h returns all the same values
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:96:in `block (3 levels) in <top (required)>'

  17) Eth::Tx#to_h does not set the binary data field
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:96:in `block (3 levels) in <top (required)>'

  18) Eth::Tx#to_h can be converted back into a transaction
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:96:in `block (3 levels) in <top (required)>'

  19) Eth::Tx#from when the signature is present 
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:146:in `block (4 levels) in <top (required)>'

  20) Eth::Tx#from when the signature does NOT match 
      Failure/Error: signature = OpenSsl.sign_compact hash, private_hex, public_hex

      NoMethodError:
        undefined method `sign_compact' for Eth::OpenSsl:Class
      # ./lib/eth/key.rb:48:in `block in sign_hash'
      # ./lib/eth/key.rb:47:in `loop'
      # ./lib/eth/key.rb:47:in `sign_hash'
      # ./lib/eth/key.rb:43:in `sign'
      # ./lib/eth/tx.rb:56:in `sign'
      # ./spec/eth/tx_spec.rb:154:in `block (4 levels) in <top (required)>'

  21) Ethereum common tests passes all the transaction tests
      Failure/Error: public_key = OpenSsl.recover_compact(signature_hash, signature)

      NoMethodError:
        undefined method `recover_compact' for Eth::OpenSsl:Class
      # ./lib/eth/tx.rb:74:in `from'
      # ./spec/ethereum_tests_spec.rb:18:in `block (4 levels) in <top (required)>'
      # ./spec/ethereum_tests_spec.rb:13:in `each'
      # ./spec/ethereum_tests_spec.rb:13:in `block (3 levels) in <top (required)>'
      # ./spec/ethereum_tests_spec.rb:12:in `each'
      # ./spec/ethereum_tests_spec.rb:12:in `block (2 levels) in <top (required)>'

Finished in 1.12 seconds (files took 0.23613 seconds to load)
65 examples, 21 failures

Failed examples:

rspec ./spec/eth/eip155_spec.rb:12 # EIP 155 and replay protection EIP155 example decodes the transaction and recognizes the signer
rspec ./spec/eth/eip155_spec.rb:39 # EIP 155 and replay protection pre-EIP155 fork decodes the transaction and recognizes the signer
rspec ./spec/eth/eip155_spec.rb:62 # EIP 155 and replay protection verifying a post-EIP155 signature with pre-EIP155 configuration cannot verify the signature
rspec ./spec/eth/eip155_spec.rb:83 # EIP 155 and replay protection verifying a pre-EIP155 signature with a post-EIP155 configuration can verify the signature
rspec ./spec/eth/key_spec.rb:26 # Eth::Key#sign signs a message so that the public key is recoverable
rspec ./spec/eth/key_spec.rb:36 # Eth::Key#sign when the network ID has been changed signs a message so that the public key is recoverable
rspec ./spec/eth/key_spec.rb:56 # Eth::Key#verify_signature signs a message so that the public key is recoverable
rspec ./spec/eth/key_spec.rb:64 # Eth::Key#verify_signature when the signature matches another public key does not verify the signature
rspec ./spec/eth/key_spec.rb:72 # Eth::Key#verify_signature when the signature does not match any public key signs a message so that the public key is recoverable
rspec ./spec/eth/key_spec.rb:80 # Eth::Key#verify_signature when the network ID has been changed can verify signatures from the new network
rspec ./spec/eth/key_spec.rb:86 # Eth::Key#verify_signature when the network ID has been changed can verify replayable signatures
rspec ./spec/eth/key_spec.rb:92 # Eth::Key#verify_signature when the network ID has been changed cannot verify signatures from other non replayable networks
rspec ./spec/eth/tx_spec.rb:69 # Eth::Tx.decode returns an instance that matches the original enocded one
rspec ./spec/eth/tx_spec.rb:74 # Eth::Tx.decode also accepts hex
rspec ./spec/eth/tx_spec.rb:86 # Eth::Tx#sign creates a recoverable signature for the transaction
rspec ./spec/eth/tx_spec.rb:98 # Eth::Tx#to_h returns all the same values
rspec ./spec/eth/tx_spec.rb:111 # Eth::Tx#to_h does not set the binary data field
rspec ./spec/eth/tx_spec.rb:116 # Eth::Tx#to_h can be converted back into a transaction
rspec ./spec/eth/tx_spec.rb:149 # Eth::Tx#from when the signature is present 
rspec ./spec/eth/tx_spec.rb:159 # Eth::Tx#from when the signature does NOT match 
rspec ./spec/ethereum_tests_spec.rb:6 # Ethereum common tests passes all the transaction tests
5chdn commented 7 years ago

Okay, I finally figured out the root cause of this issue:

FFI::NotFoundError: Function 'SSL_library_init' not found in [libssl.so]

Your implementation expects openssl versoin 1.0.x, however ArchLinux defaults to the latest openssl 1.1.x.

This lines:

if FFI::Platform.windows?
  ffi_lib 'libeay32', 'ssleay32'
else
  #ffi_lib 'ssl' ### this uses the default libssl.so which is 1.1.0.e-1 on ArchLinux
  ffi_lib 'libssl.so.1.0.0' ### This is the old 1.0.2.k-3 which provides `SSL_library_init`
end

I have no clue how to circumvent this, directly modifying the gem to hard-link agains the old version solves this issue. But I'm not sure how to tell ffi which version to use.

The main problem here is that different linux versions probably have different strategies which libssl is the default.

se3000 commented 7 years ago

Thanks for filing this, super helpful. I'll circle back once I know more.

se3000 commented 7 years ago

It looks like passing in an array will make it try each entry in the array until one succeeds.

So on a fresh ArchLinux box, after running pacman -S openssl-1.0 and updating that line to

ffi_lib ['libssl.so.1.0.0', 'ssl']

everything works again. We need to figure out support for openssl 1.1, but for now this gets things working.

se3000 commented 7 years ago

Ok, just released a new version with that line updated. Going to close this issue, feel free to reopen if I missed something. Thanks for raising the issue.

5chdn commented 7 years ago

Thanks!

tinbka commented 6 years ago

Since this is the only page googled by

RLP::Error::ObjectSerializationError: Serialization failed because of field value ('Can only serialize integers')

I get this error when I try to sign a transaction with ruby-eth:

decrypted_key = Eth::Key.decrypt key_v3_json_generated_by_geth, 'password'
### => #<Eth::Key:0x00000003e157c8 ...
tx = Eth::Tx.new(
  data: '',
  gas_limit: 21000,
  gas_price: 10_000_000,
  nonce: 10,
  to: '0xb4c4c17f9057dad5ee192b34cfb5b6a348660ea7',
  value: 1e18
)
### => #<Eth::Tx:0x000000037ed378 @_mutable=true, @data_bin="", @v=0, @r=0, @s=0, @data="", @gas_limit=21000, @gas_price=10000000, @nonce=10, @to="\xB4\xC4\xC1\x7F\x90W\xDA\xD5\xEE\x19+4\xCF\xB5\xB6\xA3Hf\x0E\xA7", @value=1.0e+18>
tx.sign decrypted_key
RLP::Error::ObjectSerializationError: Serialization failed because of field value ('Can only serialize integers')
        from (irb):13

update:

Nevermind, figured it out. The value must be an integer but 1e18 notation sets it to a float. 1e18.to_i works OK.