platon 0.2.7

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +18 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +10 -0
  6. data/Gemfile +12 -0
  7. data/Gemfile.lock +69 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +216 -0
  10. data/Rakefile +12 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/doc/zh-cn.md +1762 -0
  14. data/lib/bech32.rb +82 -0
  15. data/lib/platon.rb +77 -0
  16. data/lib/platon/abi.rb +32 -0
  17. data/lib/platon/address.rb +62 -0
  18. data/lib/platon/client.rb +175 -0
  19. data/lib/platon/contract.rb +351 -0
  20. data/lib/platon/contract_event.rb +24 -0
  21. data/lib/platon/contract_initializer.rb +54 -0
  22. data/lib/platon/decoder.rb +99 -0
  23. data/lib/platon/deployment.rb +49 -0
  24. data/lib/platon/encoder.rb +120 -0
  25. data/lib/platon/explorer_url_helper.rb +0 -0
  26. data/lib/platon/formatter.rb +142 -0
  27. data/lib/platon/function.rb +36 -0
  28. data/lib/platon/function_input.rb +13 -0
  29. data/lib/platon/function_output.rb +14 -0
  30. data/lib/platon/gas.rb +9 -0
  31. data/lib/platon/http_client.rb +55 -0
  32. data/lib/platon/initializer.rb +0 -0
  33. data/lib/platon/ipc_client.rb +45 -0
  34. data/lib/platon/key.rb +105 -0
  35. data/lib/platon/key/decrypter.rb +113 -0
  36. data/lib/platon/key/encrypter.rb +128 -0
  37. data/lib/platon/open_ssl.rb +267 -0
  38. data/lib/platon/ppos.rb +344 -0
  39. data/lib/platon/railtie.rb +0 -0
  40. data/lib/platon/secp256k1.rb +7 -0
  41. data/lib/platon/sedes.rb +40 -0
  42. data/lib/platon/segwit_addr.rb +66 -0
  43. data/lib/platon/singleton.rb +39 -0
  44. data/lib/platon/solidity.rb +40 -0
  45. data/lib/platon/transaction.rb +41 -0
  46. data/lib/platon/tx.rb +201 -0
  47. data/lib/platon/utils.rb +180 -0
  48. data/lib/platon/version.rb +5 -0
  49. data/lib/tasks/platon_contract.rake +27 -0
  50. data/platon-ruby-logo.png +0 -0
  51. data/platon.gemspec +50 -0
  52. metadata +235 -0
@@ -0,0 +1,24 @@
1
+ module Platon
2
+ class ContractEvent
3
+
4
+ attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address, :client
5
+
6
+ def initialize(data)
7
+ @name = data["name"]
8
+ @input_types = data["inputs"].collect {|x| x["type"]}
9
+ @inputs = data["inputs"].collect {|x| x["name"]}
10
+ @event_string = "#{@name}(#{@input_types.join(",")})"
11
+ @signature = Digest::SHA3.hexdigest(@event_string, 256)
12
+ end
13
+
14
+ def set_address(address)
15
+ @address = address
16
+ end
17
+
18
+ def set_client(client)
19
+ @client = client
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -0,0 +1,54 @@
1
+ module Platon
2
+
3
+ class ContractInitializer
4
+
5
+ attr_accessor :abi, :binary, :name, :libraries, :needs_linking, :project_initializer, :contract
6
+
7
+ def initialize(contract_name, contract, project_initializer)
8
+ @abi = JSON.parse(contract["abi"]) unless contract.nil?
9
+ @binary = contract["bin"] unless contract.nil?
10
+ @name = contract_name
11
+ @project_initializer = project_initializer
12
+ matchdata = @binary.scan(/_+[a-zA-Z]+_+/).uniq
13
+ @needs_linking = matchdata.present?
14
+ if @needs_linking
15
+ @libraries = matchdata.collect do |libname|
16
+ {name: libname.gsub(/_+/,''), sigil: libname}
17
+ end
18
+ end
19
+ end
20
+
21
+ def link_libraries
22
+ if @needs_linking
23
+ @libraries.each do |library|
24
+ name = library[:name]
25
+ if @project_initializer.libraries[name].nil?
26
+ ENV['ETHEREUM_DEPLOYER_WAIT_TIME'] ||= "120"
27
+ wait_time = ENV['ETHEREUM_DEPLOYER_WAIT_TIME'].to_i
28
+ library_instance = library[:name].constantize.new
29
+ puts "Deploying library #{name}"
30
+ library_instance.deploy_and_wait(wait_time)
31
+ puts "Library deployed at #{library_instance.address}"
32
+ @project_initializer.libraries[name] = library_instance.address
33
+ @binary.gsub!(library[:sigil], library_instance.address.gsub(/^0x/,''))
34
+ else
35
+ address = @project_initializer.libraries[name]
36
+ @binary.gsub!(library[:sigil], address.gsub(/^0x/,''))
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def build(connection)
43
+ @contract = Platon::Contract.new(@name, @binary, @abi, client)
44
+ @contract.build(connection)
45
+ end
46
+
47
+ def generate_javascripts(path)
48
+ data = {name: @name, abi: @abi, binary: @binary}
49
+ File.open(File.join(path, "#{@name}.json"), 'w') {|f| f.puts data.to_json}
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,99 @@
1
+ module Platon
2
+ class Decoder
3
+
4
+ def decode(type, value, start = 0)
5
+ is_array, arity, array_subtype = Abi::parse_array_type(type)
6
+ if is_array && arity
7
+ decode_static_array(arity, array_subtype, value, start)
8
+ elsif is_array
9
+ decode_dynamic_array(array_subtype, value, start)
10
+ else
11
+ value = value.gsub(/^0x/,'')
12
+ core, subtype = Abi::parse_type(type)
13
+ method_name = "decode_#{core}".to_sym
14
+ self.send(method_name, value, subtype, start)
15
+ end
16
+ end
17
+
18
+ def decode_static_array(arity, array_subtype, value, start)
19
+ (0..arity-1).map { |i| decode(array_subtype, value, start + i * 64) }
20
+ end
21
+
22
+ def decode_dynamic_array(array_subtype, value, start)
23
+ location = decode_uint(value[start..(start+63)]) * 2
24
+ size = decode_uint(value[location..location+63])
25
+ (0..size-1).map { |i| decode(array_subtype, value, location + (i+1) * 64) }
26
+ end
27
+
28
+ def decode_fixed(value, subtype = "128x128", start = 0)
29
+ decode_int(trim(value, start, fixed_bitsize(subtype))).to_f / 2**exponent(subtype)
30
+ end
31
+
32
+ def decode_uint(value, subtype = "256", start = 0)
33
+ trim(value, start, bitsize(subtype)).hex
34
+ end
35
+
36
+ def decode_int(value, subtype = "256", start = 0)
37
+ raise ArgumentError if value.nil?
38
+ size = bitsize(subtype)
39
+ value = trim(value, start, size)
40
+ (value[0..1] == "ff") ? (value.hex - (2 ** size)) : value.hex
41
+ end
42
+
43
+ def decode_bool(value, _, start)
44
+ value = trim(value, start, 4)
45
+ return true if value == "1"
46
+ return false if value == "0"
47
+ raise ArgumentError
48
+ end
49
+
50
+ def decode_address(value, _ = nil, start)
51
+ raise ArgumentError if value.size-start < 64
52
+ value[start+24..start+63]
53
+ end
54
+
55
+ def decode_bytes(value, subtype, start)
56
+ subtype.present? ? decode_static_bytes(value, subtype, start) : decode_dynamic_bytes(value, start)
57
+ end
58
+
59
+ def decode_static_bytes(value, subtype = nil, start = 0)
60
+ trim(value, start, subtype.to_i*8).scan(/.{2}/).collect {|x| x.hex}.pack('C*').strip
61
+ end
62
+
63
+ def decode_dynamic_bytes(value, start = 0)
64
+ location = decode_uint(value[start..(start+63)]) * 2
65
+ size = decode_uint(value[location..location+63]) * 2
66
+ value[location+64..location+63+size].scan(/.{2}/).collect {|x| x.hex}.pack('C*')
67
+ end
68
+
69
+ def decode_string(value, _ = nil, start = 0)
70
+ decode_dynamic_bytes(value, start).force_encoding('utf-8')
71
+ end
72
+
73
+ def decode_arguments(arguments, data)
74
+ data = data.gsub(/^0x/,'')
75
+ types = arguments.map { |o| o.type }
76
+ types.each.with_index.map { |t , i| decode(t, data, i*64) }
77
+ end
78
+
79
+ private
80
+ def trim(value, start, bitsize = 256)
81
+ value[start+63-(bitsize/4-1)..start+63]
82
+ end
83
+
84
+ def bitsize(subtype, default = 256)
85
+ subtype.present? ? subtype.to_i : default
86
+ end
87
+
88
+ def fixed_bitsize(subtype = nil)
89
+ subtype ||= "128x128"
90
+ _, x, n = /(\d+)x(\d+)/.match(subtype).to_a
91
+ x.to_i + n.to_i
92
+ end
93
+
94
+ def exponent(subtype, default = 128)
95
+ subtype.nil? ? default : /(\d+)x(\d+)/.match(subtype)[2].to_i
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,49 @@
1
+ module Platon
2
+
3
+ class Deployment
4
+
5
+ DEFAULT_TIMEOUT = 300.seconds
6
+ DEFAULT_STEP = 5.seconds
7
+
8
+ attr_accessor :id, :contract_address, :connection, :deployed, :mined
9
+ attr_reader :valid_deployment
10
+
11
+ def initialize(txid, connection)
12
+ @id = txid
13
+ @connection = connection
14
+ @deployed = false
15
+ @contract_address = nil
16
+ @valid_deployment = false
17
+ end
18
+
19
+ def mined?
20
+ return true if @mined
21
+ @mined = @connection.platon_get_transaction_by_hash(@id)["result"]["blockNumber"].present?
22
+ @mined ||= false
23
+ end
24
+
25
+ def check_deployed
26
+ return false unless @id
27
+ contract_receipt = @connection.platon_get_transaction_receipt(@id)
28
+ result = contract_receipt["result"]
29
+ has_contract_address = result && result["contractAddress"]
30
+ @contract_address ||= result["contractAddress"] if has_contract_address
31
+ has_contract_address && result["blockNumber"]
32
+ end
33
+
34
+ def deployed?
35
+ @valid_deployment ||= check_deployed
36
+ end
37
+
38
+ def wait_for_deployment(timeout: DEFAULT_TIMEOUT, step: DEFAULT_STEP)
39
+ start_time = Time.now
40
+ loop do
41
+ raise "Transaction #{@id} timed out." if ((Time.now - start_time) > timeout)
42
+ yield if block_given?
43
+ return true if deployed?
44
+ sleep step
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,120 @@
1
+ module Platon
2
+
3
+ class Encoder
4
+
5
+ def encode(type, value)
6
+ is_array, arity, array_subtype = Abi::parse_array_type(type)
7
+ if is_array && arity
8
+ encode_static_array(arity, array_subtype, value)
9
+ elsif is_array
10
+ encode_dynamic_array(array_subtype, value)
11
+ else
12
+ core, subtype = Abi::parse_type(type)
13
+ method_name = "encode_#{core}".to_sym
14
+ self.send(method_name, value, subtype)
15
+ end
16
+ end
17
+
18
+ def encode_static_array(arity, array_subtype, array)
19
+ raise "Wrong number of arguments" if arity != array.size
20
+ array.inject("") { |a, e| a << encode(array_subtype, e) }
21
+ end
22
+
23
+ def encode_dynamic_array(array_subtype, array)
24
+ location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
25
+ size = encode_uint(array.size)
26
+ data = array.inject("") { |a, e| a << encode(array_subtype, e) }
27
+ [location, size + data]
28
+ end
29
+
30
+ def encode_int(value, _ = nil)
31
+ to_twos_complement(value).to_s(16).rjust(64, '0')
32
+ end
33
+
34
+ def encode_uint(value, _ = nil)
35
+ raise ArgumentError if value < 0
36
+ encode_int(value)
37
+ end
38
+
39
+ def encode_bool(value, _)
40
+ (value ? "1" : "0").rjust(64, '0')
41
+ end
42
+
43
+ def encode_fixed(value, subtype)
44
+ n = subtype.nil? ? 128 : /(\d+)x(\d+)/.match(subtype)[2].to_i
45
+ do_encode_fixed(value, n)
46
+ end
47
+
48
+ def do_encode_fixed(value, n)
49
+ encode_uint((value * 2**n).to_i)
50
+ end
51
+
52
+ def encode_ufixed(_value, _)
53
+ raise NotImplementedError
54
+ end
55
+
56
+ def encode_bytes(value, subtype)
57
+ subtype.nil? ? encode_dynamic_bytes(value) : encode_static_bytes(value)
58
+ end
59
+
60
+ def encode_static_bytes(value)
61
+ value.bytes.map {|x| x.to_s(16).rjust(2, '0')}.join("").ljust(64, '0')
62
+ end
63
+
64
+ def encode_dynamic_bytes(value)
65
+ location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
66
+ size = encode_uint(value.size)
67
+ content = encode_static_bytes(value)
68
+ [location, size + content]
69
+ end
70
+
71
+ def encode_string(value, _)
72
+ location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
73
+ size = encode_uint(value.bytes.size)
74
+ content = value.bytes.map {|x| x.to_s(16).rjust(2, '0')}.join("").ljust(64, '0')
75
+ [location, size + content]
76
+ end
77
+
78
+ def encode_address(value, _)
79
+ # puts "value: #{value}"
80
+ value = Utils.decode_bech32_address(value) if Utils.is_bech32_address?(value)
81
+ value = "0" * 24 + value.gsub(/^0x/,'')
82
+ raise ArgumentError if value.size != 64
83
+ value
84
+ end
85
+
86
+ def ensure_prefix(value)
87
+ value.start_with?("0x") ? value : ("0x" + value)
88
+ end
89
+
90
+ def encode_arguments(inputs, args)
91
+ raise "Wrong number of arguments" if inputs.length != args.length
92
+ @head = ""
93
+ @tail = ""
94
+ @inputs = inputs
95
+ inputs.each.with_index do |input, index|
96
+ encoded = encode(input.type, args[index])
97
+ if encoded.is_a? Array
98
+ @head << encoded[0]
99
+ @tail << encoded[1]
100
+ else
101
+ @head << encoded
102
+ end
103
+ end
104
+ @head + @tail
105
+ end
106
+
107
+ private
108
+ def to_twos_complement(number)
109
+ (number & ((1 << 256) - 1))
110
+ end
111
+
112
+ def size_of_inputs(inputs)
113
+ inputs.map do |input|
114
+ _, arity, _ = Abi::parse_array_type(input.type)
115
+ arity.nil? ? 32 : arity * 32
116
+ end.inject(:+)
117
+ end
118
+ end
119
+
120
+ end
File without changes
@@ -0,0 +1,142 @@
1
+ module Platon
2
+ class Formatter
3
+
4
+ UNITS = {
5
+ 'von': 1,
6
+ 'kvon': 1000,
7
+ 'mvon': 1000000,
8
+ 'gvon': 1000000000, ## 10 ** 9
9
+ 'microatp': 1000000000000,
10
+ 'milliatp': 1000000000000000,
11
+ 'atp': 1000000000000000000, ## 10 ** 18
12
+ 'katp': 1000000000000000000000,
13
+ 'matp': 1000000000000000000000000,
14
+ 'gatp': 1000000000000000000000000000,
15
+ 'tatp': 1000000000000000000000000000000
16
+ }
17
+
18
+ def valid_address?(address_string)
19
+ address = address_string.gsub(/^0x/,'')
20
+ return false if address == "0000000000000000000000000000000000000000"
21
+ return false if address.length != 40
22
+ return !(address.match(/[0-9a-fA-F]+/).nil?)
23
+ end
24
+
25
+ def from_bool(boolval)
26
+ return nil if boolval.nil?
27
+ boolval ? "1" : "0"
28
+ end
29
+
30
+ def to_bool(hexstring)
31
+ return nil if hexstring.nil?
32
+ (hexstring == "0000000000000000000000000000000000000000000000000000000000000001")
33
+ end
34
+
35
+ def to_ascii(hexstring)
36
+ return nil if hexstring.nil?
37
+ hexstring.gsub(/^0x/,'').scan(/.{2}/).collect {|x| x.hex}.pack("c*")
38
+ end
39
+
40
+ def to_utf8(hexstring)
41
+ return nil if hexstring.nil?
42
+ hexstring.gsub(/^0x/,'').scan(/.{2}/).collect {|x| x.hex}.pack("U*").delete("\u0000")
43
+ end
44
+
45
+ def from_ascii(ascii_string)
46
+ return nil if ascii_string.nil?
47
+ ascii_string.unpack('H*')[0]
48
+ end
49
+
50
+ def from_utf8(utf8_string)
51
+ return nil if utf8_string.nil?
52
+ utf8_string.force_encoding('UTF-8').split("").collect {|x| x.ord.to_s(16).rjust(2, '0')}.join("")
53
+ end
54
+
55
+ def to_address(hexstring)
56
+ return "0x0000000000000000000000000000000000000000" if hexstring.nil?
57
+ "0x" + hexstring[-40..-1]
58
+ end
59
+
60
+ def to_von(amount, unit = "atp") #TODO
61
+ return nil if amount.nil?
62
+ BigDecimal(UNITS[unit.to_sym] * amount, 16).to_s.to_i rescue nil
63
+ end
64
+
65
+ def from_von(amount, unit = "atp") #TODO
66
+ return nil if amount.nil?
67
+ (BigDecimal(amount, 16) / BigDecimal(UNITS[unit.to_sym], 16)).to_s rescue nil
68
+ end
69
+
70
+ def to_gvon(amount, unit = "gvon")
71
+ return nil if amount.nil?
72
+ BigDecimal(UNITS[unit.to_sym] * amount, 16).to_s.to_i rescue nil
73
+ end
74
+
75
+ def from_gvon(amount, unit = "gvon")
76
+ return nil if amount.nil?
77
+ (BigDecimal(amount, 16) / BigDecimal(UNITS[unit.to_sym], 16)).to_s rescue nil
78
+ end
79
+
80
+ def from_address(address)
81
+ return "0x0000000000000000000000000000000000000000" if address.nil?
82
+ address.gsub(/^0x/,'').rjust(64, "0")
83
+ end
84
+
85
+ def to_param(string)
86
+ string.ljust(64, '0')
87
+ end
88
+
89
+ def from_input(string)
90
+ string[10..-1].scan(/.{64}/)
91
+ end
92
+
93
+ def to_twos_complement(number)
94
+ (number & ((1 << 256) - 1)).to_s(16)
95
+ end
96
+
97
+ def to_int(hexstring)
98
+ return nil if hexstring.nil?
99
+ (hexstring.gsub(/^0x/,'')[0..1] == "ff") ? (hexstring.hex - (2 ** 256)) : hexstring.hex
100
+ end
101
+
102
+ def get_base_type(typename)
103
+ typename.gsub(/\d+/,'')
104
+ end
105
+
106
+ def from_payload(args)
107
+ converter = "output_to_#{self.get_base_type(args[0])}".to_sym
108
+ self.send(converter, args[1])
109
+ end
110
+
111
+ def output_to_address(bytes)
112
+ self.to_address(bytes)
113
+ end
114
+
115
+ def output_to_bytes(bytes)
116
+ self.to_utf8(bytes)
117
+ end
118
+
119
+ def output_to_string(bytes)
120
+ self.to_utf8(bytes)
121
+ end
122
+
123
+ def output_to_uint(bytes)
124
+ self.to_int(bytes)
125
+ end
126
+
127
+ def output_to_int(bytes)
128
+ self.to_int(bytes)
129
+ end
130
+
131
+ def output_to_bool(bytes)
132
+ self.to_bool(bytes.gsub(/^0x/,''))
133
+ end
134
+
135
+ def to_output(args)
136
+ converter = "output_to_#{self.get_base_type(args[0])}".to_sym
137
+ self.send(converter, args[1])
138
+ end
139
+
140
+ end
141
+
142
+ end