Closed 5chdn closed 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
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.
Thanks for filing this, super helpful. I'll circle back once I know more.
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.
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.
Thanks!
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.
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:
Not sure, is it an ruby-eth bug or am I missing something?