eth 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3920e84b3cefbb7da9607e92c438654b016a7712
4
- data.tar.gz: 751fa67b78a3082ae3b3afdb9f7ed0f135c7217c
3
+ metadata.gz: 3634eb14f8b7215034c3d182aaa6f1617062e723
4
+ data.tar.gz: abf2f132aa8eb36db20498fa762543ec5d243d81
5
5
  SHA512:
6
- metadata.gz: d967fb582e3d63a94a5fdca95eebffb8a0462e4e1a1aadab65e6df2cc11bd0e552d39f687b047a430dc24e204021aab0e3dd59eecb88c31b56843d6603e04ba9
7
- data.tar.gz: d61baf72a91f9d7836609f0d50c030128202a40abf4e25092b5ff9d1c6f3ca3a8be1357621bbff0c8b62d5d1a953e0ef3a73bef3bdc5c409bb0773619d49c213
6
+ metadata.gz: cfc6c93a18eb92381052080ecdfffeaf017cb119954642dba89d8dcf3fe8ee0f505f652c979c4a9b2067375acb4625a29b130b517f5dfaff0e76a8ea459dc4ab
7
+ data.tar.gz: 36b54f235dc2256dbd705c3cd7ea235095f9323f09b32f36903712363d687b21de4d553a74b4b92071898c1daf81a1459cd60d0c2675e403dbe03b034e381237
@@ -0,0 +1,3 @@
1
+ [submodule "spec/fixtures/ethereum_tests"]
2
+ path = spec/fixtures/ethereum_tests
3
+ url = git@github.com:ethereum/tests.git
@@ -0,0 +1,21 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## [0.4.0]
8
+
9
+ ### Added
10
+ - Tx#data_bin returns the data field of a transaction in binary.
11
+ - Tx#data_hex returns the data field of a transaction as a hexadecimal string.
12
+ - Tx#id is an alias of Tx#hash
13
+
14
+ ### Changed
15
+ - Tx#data is configurable to return either hex or binary: `config.tx_data_hex = true`.
16
+ - Tx#hash includes the '0x' hex prefix.
17
+ - Tx#hex includes the '0x' hex prefix.
18
+ - Key#address getter is prepended by '0x'.
19
+ - Extract public key to address method into Utils.public_key_to_address.
20
+ - Tx#from returns an address instead of a public key.
21
+ - Chain ID is updated to the later version of the spec.
data/README.md CHANGED
@@ -35,11 +35,11 @@ old_key = Eth::Key.new priv: private_key
35
35
  Build a transaction from scratch:
36
36
  ```ruby
37
37
  tx = Eth::Tx.new({
38
- data: 'abcdef',
39
- gas_limit: 3_141_592,
40
- gas_price: 20_000_000_000,
41
- nonce: 0,
42
- to: key.address,
38
+ data: hex_data,
39
+ gas_limit: 21_000,
40
+ gas_price: 3_141_592,
41
+ nonce: 1,
42
+ to: key2.address,
43
43
  value: 1_000_000_000_000,
44
44
  })
45
45
  ```
@@ -50,9 +50,9 @@ tx = Eth::Tx.decode hex
50
50
 
51
51
  ### Configure
52
52
  In order to prevent replay attacks, you must specify which Ethereum chain your transactions are created for. See [EIP 155](https://github.com/ethereum/EIPs/issues/155) for more detail.
53
- ```
53
+ ```ruby
54
54
  Eth.configure do |config|
55
- config.chain_id = 18 #defaults to 13
55
+ config.chain_id = 1 # nil by default, meaning valid on any chain
56
56
  end
57
57
  ```
58
58
 
@@ -65,7 +65,19 @@ Get the raw transaction with `tx.hex`, and broadcast it through any Ethereum nod
65
65
 
66
66
  ## Contributing
67
67
 
68
- Bug reports and pull requests are welcome on GitHub at https://github.com/se3000/ethereum-tx.
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/se3000/ethereum-tx. Tests are encouraged.
69
+
70
+ ### Tests
71
+
72
+ First install the [Ethereum common tests](https://github.com/ethereum/tests):
73
+ ```shell
74
+ git submodule update --init
75
+ ```
76
+
77
+ Then run the associated tests:
78
+ ```shell
79
+ rspec
80
+ ```
69
81
 
70
82
 
71
83
  ## License
data/lib/eth.rb CHANGED
@@ -5,8 +5,6 @@ require 'money-tree'
5
5
  require 'rlp'
6
6
 
7
7
  module Eth
8
- REPLAYABLE_CHAIN_ID = 13
9
-
10
8
  autoload :Key, 'eth/key'
11
9
  autoload :OpenSsl, 'eth/open_ssl'
12
10
  autoload :Sedes, 'eth/sedes'
@@ -18,24 +16,32 @@ module Eth
18
16
  yield(configuration)
19
17
  end
20
18
 
21
- def chain_id
22
- (configuration.chain_id || REPLAYABLE_CHAIN_ID).to_i
19
+ def replayable_chain_id
20
+ 27
23
21
  end
24
22
 
25
- def v_base
26
- (chain_id * 2) + 1
23
+ def chain_id
24
+ configuration.chain_id
27
25
  end
28
26
 
29
- def replayable_v_base
30
- (REPLAYABLE_CHAIN_ID * 2) + 1
27
+ def v_base
28
+ if chain_id
29
+ (chain_id * 2) + 35
30
+ else
31
+ replayable_chain_id
32
+ end
31
33
  end
32
34
 
33
35
  def prevent_replays?
34
- chain_id != REPLAYABLE_CHAIN_ID
36
+ !chain_id.nil?
35
37
  end
36
38
 
37
39
  def replayable_v?(v)
38
- [replayable_v_base, replayable_v_base + 1].include? v
40
+ [replayable_chain_id, replayable_chain_id + 1].include? v
41
+ end
42
+
43
+ def tx_data_hex?
44
+ !!configuration.tx_data_hex
39
45
  end
40
46
 
41
47
 
@@ -47,6 +53,10 @@ module Eth
47
53
  end
48
54
 
49
55
  class Configuration
50
- attr_accessor :chain_id
56
+ attr_accessor :chain_id, :tx_data_hex
57
+
58
+ def initialize
59
+ self.tx_data_hex = true
60
+ end
51
61
  end
52
62
  end
@@ -21,12 +21,9 @@ module Eth
21
21
  end
22
22
 
23
23
  def address
24
- Utils.bin_to_hex(Utils.keccak256(public_bytes[1..-1])[-20..-1])
25
- end
26
-
27
- def to_address
28
- address
24
+ Utils.public_key_to_address public_hex
29
25
  end
26
+ alias_method :to_address, :address
30
27
 
31
28
  def sign(message)
32
29
  sign_hash message_hash(message)
@@ -163,7 +163,7 @@ module Eth
163
163
  return false if signature.bytesize != 65
164
164
 
165
165
  version = signature.unpack('C')[0]
166
- v_base = Eth.replayable_v?(version) ? Eth.replayable_v_base : Eth.v_base
166
+ v_base = Eth.replayable_v?(version) ? Eth.replayable_chain_id : Eth.v_base
167
167
  return false if version < v_base
168
168
 
169
169
  compressed = false
@@ -10,7 +10,7 @@ module Eth
10
10
  gas_limit: big_endian_int,
11
11
  to: address,
12
12
  value: big_endian_int,
13
- data: binary,
13
+ data_bin: binary,
14
14
  v: big_endian_int,
15
15
  r: big_endian_int,
16
16
  s: big_endian_int
@@ -19,14 +19,18 @@ module Eth
19
19
  attr_writer :signature
20
20
 
21
21
  def self.decode(data)
22
- data = Utils.hex_to_bin(data) if data.match(/\A\h+\Z/)
22
+ data = Utils.hex_to_bin(data) if data.match(/\A(?:0x)?\h+\Z/)
23
23
  deserialize(RLP.decode data)
24
24
  end
25
25
 
26
- def initialize(*args)
27
- fields = {v: 0, r: 0, s: 0}.merge parse_field_args(args)
26
+ def initialize(params)
27
+ fields = {v: 0, r: 0, s: 0}.merge params
28
28
  fields[:to] = Utils.normalize_address(fields[:to])
29
29
 
30
+ if params[:data]
31
+ self.data = params.delete(:data)
32
+ fields[:data_bin] = data_bin
33
+ end
30
34
  serializable_initialize fields
31
35
 
32
36
  check_transaction_validity
@@ -37,7 +41,7 @@ module Eth
37
41
  end
38
42
 
39
43
  def signing_data
40
- Utils.bin_to_hex unsigned_encoded
44
+ Utils.bin_to_prefixed_hex unsigned_encoded
41
45
  end
42
46
 
43
47
  def encoded
@@ -45,42 +49,72 @@ module Eth
45
49
  end
46
50
 
47
51
  def hex
48
- Utils.bin_to_hex encoded
52
+ Utils.bin_to_prefixed_hex encoded
49
53
  end
50
54
 
51
55
  def sign(key)
52
56
  self.signature = key.sign(unsigned_encoded)
53
- self.vrs = Utils.v_r_s_for signature
57
+ vrs = Utils.v_r_s_for signature
58
+ self.v = vrs[0]
59
+ self.r = vrs[1]
60
+ self.s = vrs[2]
54
61
 
55
62
  self
56
63
  end
57
64
 
58
65
  def to_h
59
- self.class.serializable_fields.keys.inject({}) do |hash, field|
66
+ hash_keys.inject({}) do |hash, field|
60
67
  hash[field] = send field
61
68
  hash
62
69
  end
63
70
  end
64
71
 
65
72
  def from
66
- return @from if @from
67
- @from ||= OpenSsl.recover_compact(signature_hash, signature) if signature
73
+ if signature
74
+ public_key = OpenSsl.recover_compact(signature_hash, signature)
75
+ Utils.public_key_to_address(public_key) if public_key
76
+ end
68
77
  end
69
78
 
70
79
  def signature
71
80
  return @signature if @signature
72
- self.signature = [v, r, s].map do |integer|
73
- Utils.int_to_base256 integer
74
- end.join if [v, r, s].all?
81
+ self.signature = [
82
+ Utils.int_to_base256(v),
83
+ Utils.zpad_int(r),
84
+ Utils.zpad_int(s),
85
+ ].join if [v, r, s].all?
75
86
  end
76
87
 
77
88
  def hash
78
89
  Utils.bin_to_hex Utils.keccak256_rlp(self)
79
90
  end
91
+ alias_method :id, :hash
92
+
93
+ def data_hex
94
+ Utils.bin_to_prefixed_hex data_bin
95
+ end
96
+
97
+ def data_hex=(hex)
98
+ self.data_bin = Utils.hex_to_bin(hex)
99
+ end
100
+
101
+ def data
102
+ Eth.tx_data_hex? ? data_hex : data_bin
103
+ end
104
+
105
+ def data=(string)
106
+ Eth.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
107
+ end
80
108
 
81
109
 
82
110
  private
83
111
 
112
+ def hash_keys
113
+ keys = self.class.serializable_fields.keys
114
+ keys.delete(:data_bin)
115
+ keys + [:data]
116
+ end
117
+
84
118
  def check_transaction_validity
85
119
  if [gas_price, gas_limit, value, nonce].max > Ethereum::Base::UINT_MAX
86
120
  raise Ethereum::Base::InvalidTransaction, "Values way too high!"
@@ -89,15 +123,9 @@ module Eth
89
123
  end
90
124
  end
91
125
 
92
- def vrs=(vrs)
93
- self.v = vrs[0]
94
- self.r = vrs[1]
95
- self.s = vrs[2]
96
- end
97
-
98
126
  def intrinsic_gas_used
99
- num_zero_bytes = data.count(Ethereum::Base::BYTE_ZERO)
100
- num_non_zero_bytes = data.size - num_zero_bytes
127
+ num_zero_bytes = data_bin.count(Ethereum::Base::BYTE_ZERO)
128
+ num_non_zero_bytes = data_bin.size - num_zero_bytes
101
129
 
102
130
  Ethereum::Base::GTXCOST +
103
131
  Ethereum::Base::GTXDATAZERO * num_zero_bytes +
@@ -1,5 +1,4 @@
1
1
  module Eth
2
-
3
2
  module Utils
4
3
 
5
4
  extend Ethereum::Base::Utils
@@ -22,7 +21,7 @@ module Eth
22
21
  end
23
22
 
24
23
  def hex_to_bin(string)
25
- [string].pack("H*")
24
+ [string.sub(/\A0x/, '')].pack("H*")
26
25
  end
27
26
 
28
27
  def base256_to_int(string)
@@ -49,5 +48,27 @@ module Eth
49
48
  ]
50
49
  end
51
50
 
51
+ def prefix_hex(hex)
52
+ hex.match(/\A0x/) ? hex : "0x#{hex}"
53
+ end
54
+
55
+ def bin_to_prefixed_hex(binary)
56
+ prefix_hex bin_to_hex(binary)
57
+ end
58
+
59
+ def public_key_to_address(hex)
60
+ bytes = hex_to_bin(hex)
61
+ address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
62
+ bin_to_prefixed_hex address_bytes
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def lpad(x, symbol, l)
69
+ return x if x.size >= l
70
+ symbol * (l - x.size) + x
71
+ end
72
+
52
73
  end
53
74
  end
@@ -1,3 +1,3 @@
1
1
  module Eth
2
- VERSION = "0.3.4"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Ellis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-21 00:00:00.000000000 Z
11
+ date: 2017-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ethereum-base
@@ -130,8 +130,10 @@ extensions: []
130
130
  extra_rdoc_files: []
131
131
  files:
132
132
  - ".gitignore"
133
+ - ".gitmodules"
133
134
  - ".rspec"
134
135
  - ".travis.yml"
136
+ - CHANGELOG.md
135
137
  - Gemfile
136
138
  - LICENSE.txt
137
139
  - README.md