eth 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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