cryptocoin 0.0.1b
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +2 -0
- data/cryptocoin.gemspec +24 -0
- data/lib/cryptocoin/core_ext/integer.rb +24 -0
- data/lib/cryptocoin/core_ext/string.rb +30 -0
- data/lib/cryptocoin/digest.rb +36 -0
- data/lib/cryptocoin/merkle_tree.rb +78 -0
- data/lib/cryptocoin/network/bitcoin.rb +9 -0
- data/lib/cryptocoin/network/dogecoin.rb +9 -0
- data/lib/cryptocoin/network/litecoin.rb +9 -0
- data/lib/cryptocoin/network.rb +53 -0
- data/lib/cryptocoin/protocol/block_header.rb +58 -0
- data/lib/cryptocoin/protocol/inventory_vector.rb +28 -0
- data/lib/cryptocoin/protocol/message/addr.rb +29 -0
- data/lib/cryptocoin/protocol/message/alert.rb +0 -0
- data/lib/cryptocoin/protocol/message/block.rb +13 -0
- data/lib/cryptocoin/protocol/message/getaddr.rb +17 -0
- data/lib/cryptocoin/protocol/message/getblocks.rb +44 -0
- data/lib/cryptocoin/protocol/message/getdata.rb +31 -0
- data/lib/cryptocoin/protocol/message/getheaders.rb +44 -0
- data/lib/cryptocoin/protocol/message/headers.rb +30 -0
- data/lib/cryptocoin/protocol/message/inv.rb +31 -0
- data/lib/cryptocoin/protocol/message/mempool.rb +16 -0
- data/lib/cryptocoin/protocol/message/notfound.rb +31 -0
- data/lib/cryptocoin/protocol/message/ping.rb +24 -0
- data/lib/cryptocoin/protocol/message/pong.rb +24 -0
- data/lib/cryptocoin/protocol/message/reject.rb +54 -0
- data/lib/cryptocoin/protocol/message/tx.rb +11 -0
- data/lib/cryptocoin/protocol/message/verack.rb +16 -0
- data/lib/cryptocoin/protocol/message/version.rb +59 -0
- data/lib/cryptocoin/protocol/message.rb +27 -0
- data/lib/cryptocoin/protocol/net_addr.rb +55 -0
- data/lib/cryptocoin/protocol/packet.rb +74 -0
- data/lib/cryptocoin/protocol/var_len_int.rb +85 -0
- data/lib/cryptocoin/protocol/var_len_str.rb +18 -0
- data/lib/cryptocoin/protocol.rb +8 -0
- data/lib/cryptocoin/script/op_code/constants.rb +157 -0
- data/lib/cryptocoin/script/op_code/functions.rb +515 -0
- data/lib/cryptocoin/script/op_code.rb +59 -0
- data/lib/cryptocoin/script.rb +234 -0
- data/lib/cryptocoin/structure/address.rb +64 -0
- data/lib/cryptocoin/structure/block.rb +109 -0
- data/lib/cryptocoin/structure/key_pair.rb +57 -0
- data/lib/cryptocoin/structure/merkle_branch.rb +37 -0
- data/lib/cryptocoin/structure/transaction/input.rb +80 -0
- data/lib/cryptocoin/structure/transaction/output.rb +49 -0
- data/lib/cryptocoin/structure/transaction.rb +94 -0
- data/lib/cryptocoin/version.rb +3 -0
- data/lib/cryptocoin.rb +29 -0
- data/spec/script_spec.rb +42 -0
- data/spec/spec_helper.rb +20 -0
- metadata +145 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Getheaders
|
5
|
+
attr_reader :digest_count
|
6
|
+
|
7
|
+
def parse_from_raw(payload)
|
8
|
+
block_locator_digests, i = [], 0
|
9
|
+
version = payload[0..3]
|
10
|
+
digest_count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(payload[4..-1])
|
11
|
+
digest_count.times do
|
12
|
+
c = digest_count.raw.bytesize+i*32
|
13
|
+
block_locator_digests.push(payload[c..c+31])
|
14
|
+
i+=1
|
15
|
+
end
|
16
|
+
digest_stop = payload[5+i*32..-1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(version, digest_count, block_locator_digests, digest_stop)
|
20
|
+
@version_raw = version
|
21
|
+
@digest_count = digest_count
|
22
|
+
@block_locator_digests_raw = block_locator_digests
|
23
|
+
@digest_stop_raw = digest_stop
|
24
|
+
end
|
25
|
+
|
26
|
+
def version
|
27
|
+
@version ||= @version_raw.unpack('L')[0]
|
28
|
+
end
|
29
|
+
|
30
|
+
def block_locator_digests
|
31
|
+
@block_locator_digests ||= @block_locator_digests_raw.map{|e| e.unpack('H*')[0] }
|
32
|
+
end
|
33
|
+
|
34
|
+
def digest_stop
|
35
|
+
@digest_stop ||= @digest_stop_raw.unpack('H*')[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
def raw
|
39
|
+
@version_raw + @digest_count.raw + @block_locator_digests_raw.join + @digest_stop_raw
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'cryptocoin/protocol/block_header'
|
2
|
+
|
3
|
+
module Cryptocoin
|
4
|
+
module Protocol
|
5
|
+
class Message
|
6
|
+
class Headers
|
7
|
+
attr_reader :count, :headers
|
8
|
+
def self.parse_from_raw(payload)
|
9
|
+
headers, i = [], 0
|
10
|
+
count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(payload)
|
11
|
+
count.times do
|
12
|
+
c = count.raw.bytesize + i*81
|
13
|
+
headers.push(Cryptocoin::Protocol::BlockHeader.parse_from_raw(payload[c..c+80]))
|
14
|
+
i+=1
|
15
|
+
end
|
16
|
+
self.new(count, headers)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(count, headers)
|
20
|
+
@count = count
|
21
|
+
@headers = headers
|
22
|
+
end
|
23
|
+
|
24
|
+
def raw
|
25
|
+
@count.raw + @headers.map{|e| e.raw}.join
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'cryptocoin/protocol/inventory_vector'
|
2
|
+
require 'cryptocoin/protocol/var_len_int'
|
3
|
+
|
4
|
+
module Cryptocoin
|
5
|
+
module Protocol
|
6
|
+
class Message
|
7
|
+
class Inv
|
8
|
+
def self.parse_from_raw(payload)
|
9
|
+
inventory = []
|
10
|
+
i = 0
|
11
|
+
count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(payload)
|
12
|
+
count.times do
|
13
|
+
c = count.raw.bytesize+i*36
|
14
|
+
inventory.push(Cryptocoin::Protocol::InventoryVector.parse_from_raw(payload[c..c+35]))
|
15
|
+
i+=1
|
16
|
+
end
|
17
|
+
self.new(count, inventory)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(count, inventory)
|
21
|
+
@count_raw = count
|
22
|
+
@inventory = inventory
|
23
|
+
end
|
24
|
+
|
25
|
+
def raw
|
26
|
+
@count_raw + @inventory.map{|e| e.raw}.join
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Mempool
|
5
|
+
def self.parse_from_raw(payload)
|
6
|
+
# https://en.bitcoin.it/wiki/Protocol_specification#mempool
|
7
|
+
# No data is sent with this message
|
8
|
+
self.new
|
9
|
+
end
|
10
|
+
def raw
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'cryptocoin/protocol/inventory_vector'
|
2
|
+
require 'cryptocoin/protocol/var_len_int'
|
3
|
+
|
4
|
+
module Cryptocoin
|
5
|
+
module Protocol
|
6
|
+
class Message
|
7
|
+
class Notfound
|
8
|
+
def self.parse_from_raw(payload)
|
9
|
+
inventory = []
|
10
|
+
i = 0
|
11
|
+
count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(payload)
|
12
|
+
count.times do
|
13
|
+
c = count.raw.bytesize+i*36
|
14
|
+
inventory.push(Cryptocoin::Protocol::InventoryVector.parse_from_raw(payload[c..c+35]))
|
15
|
+
i+=1
|
16
|
+
end
|
17
|
+
self.new(count, inventory)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(count, inventory)
|
21
|
+
@count_raw = count
|
22
|
+
@inventory = inventory
|
23
|
+
end
|
24
|
+
|
25
|
+
def raw
|
26
|
+
@count_raw + @inventory.map{|e| e.raw}.join
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Ping
|
5
|
+
def self.parse_from_raw(payload)
|
6
|
+
nonce = payload
|
7
|
+
self.new(nonce)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(nonce)
|
11
|
+
@nonce_raw = nonce
|
12
|
+
end
|
13
|
+
|
14
|
+
def nonce
|
15
|
+
@nonce ||= @nonce_raw.unpack('Q')[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw
|
19
|
+
@nonce_raw
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Pong
|
5
|
+
def self.parse_from_raw(payload)
|
6
|
+
nonce = payload
|
7
|
+
self.new(nonce)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(nonce)
|
11
|
+
@nonce_raw = nonce
|
12
|
+
end
|
13
|
+
|
14
|
+
def nonce
|
15
|
+
@nonce ||= @nonce_raw.unpack('Q')[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw
|
19
|
+
@nonce_raw
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'cryptocoin/protocol/var_len_str'
|
2
|
+
|
3
|
+
module Cryptocoin
|
4
|
+
module Protocol
|
5
|
+
class Message
|
6
|
+
class Reject
|
7
|
+
attr_reader :message, :reason
|
8
|
+
|
9
|
+
def self.parse_from_raw(payload)
|
10
|
+
message = Cryptocoin::Protocol::VarLenStr.parse_from_raw(payload)
|
11
|
+
c = message.raw.bytesize
|
12
|
+
ccode = payload[c..c]
|
13
|
+
reason = Cryptocoin::Protocol::VarLenStr.parse_from_raw(payload[c+1..-1])
|
14
|
+
self.new(message, ccode, reason)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(message, ccode, reason)
|
18
|
+
@message = message
|
19
|
+
@ccode_raw = ccode
|
20
|
+
@reason = reason
|
21
|
+
end
|
22
|
+
|
23
|
+
def ccode
|
24
|
+
@ccode ||= @ccode_raw.unpack('H*')[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
def ccode_name
|
28
|
+
case ccode
|
29
|
+
when '1'
|
30
|
+
'REJECT_MALFORMED'
|
31
|
+
when '10'
|
32
|
+
'REJECT_INVALID'
|
33
|
+
when '11'
|
34
|
+
'REJECT_OBSOLETE'
|
35
|
+
when '12'
|
36
|
+
'REJECT_DUPLICATE'
|
37
|
+
when '40'
|
38
|
+
'REJECT_NONSTANDARD'
|
39
|
+
when '41'
|
40
|
+
'REJECT_DUST'
|
41
|
+
when '42'
|
42
|
+
'REJECT_INSUFFICIENTFEE'
|
43
|
+
when '43'
|
44
|
+
'REJECT_CHECKPOINT'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def raw
|
49
|
+
@message.raw + @ccode_raw + @reason.raw
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Verack
|
5
|
+
def self.parse_from_raw(payload)
|
6
|
+
# https://en.bitcoin.it/wiki/Protocol_specification#verack
|
7
|
+
# Has no payload
|
8
|
+
self.new
|
9
|
+
end
|
10
|
+
def raw
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class Message
|
4
|
+
class Version
|
5
|
+
def self.parse_from_raw(payload)
|
6
|
+
version = payload[0..3]
|
7
|
+
services = payload[4..11]
|
8
|
+
timestamp = payload[12..19]
|
9
|
+
address_received = Cryptocoin::Protocol::NetAddr.parse_from_raw(payload[20..45])
|
10
|
+
address_from = Cryptocoin::Protocol::NetAddr.parse_from_raw(payload[46..71])
|
11
|
+
nonce = payload[71..79]
|
12
|
+
user_agent = Cryptocoin::Protocol::VarLenStr.parse_from_raw(payload[80..-1])
|
13
|
+
start_height = payload[-5..-2]
|
14
|
+
relay = payload[-1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(version, services, timestamp, address_received, address_from, nonce, user_agent, start_height, relay)
|
18
|
+
@version_raw = version
|
19
|
+
@services_raw = services
|
20
|
+
@timestamp_raw = timestamp
|
21
|
+
@address_received = address_received
|
22
|
+
@address_from = address_from
|
23
|
+
@nonce_raw = nonce
|
24
|
+
@user_agent = user_agent
|
25
|
+
@start_height_raw = start_height
|
26
|
+
@relay_raw = relay
|
27
|
+
end
|
28
|
+
|
29
|
+
def version
|
30
|
+
@version ||= @version_raw.unpack('l')[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def services
|
34
|
+
@services ||= @services_raw.unpack('Q')[0]
|
35
|
+
end
|
36
|
+
|
37
|
+
def timestamp
|
38
|
+
@timestamp ||= @timestamp_raw.unpack('q')[0]
|
39
|
+
end
|
40
|
+
|
41
|
+
def nonce
|
42
|
+
@nonce ||= @nonce_raw.unpack('Q')[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_height
|
46
|
+
@start_height ||= @start_height_raw.unpack('l')[0]
|
47
|
+
end
|
48
|
+
|
49
|
+
def relay
|
50
|
+
@relay ||= @relay_raw.unpack('c')[0]
|
51
|
+
end
|
52
|
+
|
53
|
+
def raw
|
54
|
+
@version_raw + @services_raw + @timestamp_raw + @address_received.raw + @address_from.raw + @nonce_raw + @user_agent.raw + @start_height_raw + @relay_raw
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cryptocoin/protocol/message/addr'
|
2
|
+
require 'cryptocoin/protocol/message/alert'
|
3
|
+
require 'cryptocoin/protocol/message/block'
|
4
|
+
require 'cryptocoin/protocol/message/getaddr'
|
5
|
+
require 'cryptocoin/protocol/message/getblocks'
|
6
|
+
require 'cryptocoin/protocol/message/getdata'
|
7
|
+
require 'cryptocoin/protocol/message/getheaders'
|
8
|
+
require 'cryptocoin/protocol/message/headers'
|
9
|
+
require 'cryptocoin/protocol/message/inv'
|
10
|
+
require 'cryptocoin/protocol/message/mempool'
|
11
|
+
require 'cryptocoin/protocol/message/notfound'
|
12
|
+
require 'cryptocoin/protocol/message/ping'
|
13
|
+
require 'cryptocoin/protocol/message/pong'
|
14
|
+
require 'cryptocoin/protocol/message/reject'
|
15
|
+
require 'cryptocoin/protocol/message/tx'
|
16
|
+
require 'cryptocoin/protocol/message/verack'
|
17
|
+
require 'cryptocoin/protocol/message/version'
|
18
|
+
|
19
|
+
module Cryptocoin
|
20
|
+
module Protocol
|
21
|
+
class Message
|
22
|
+
def self.parse(command, payload)
|
23
|
+
Cryptocoin::Protocol::Message.const_get(command.capitalize).parse_from_raw(payload)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class NetAddr
|
4
|
+
def self.parse_from_raw(raw)
|
5
|
+
timestamp = raw[0..3]
|
6
|
+
services = raw[4..11]
|
7
|
+
address = raw[12..27]
|
8
|
+
port = raw[28..29]
|
9
|
+
self.new(timestamp, services, address, port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(timestamp, services, address, port)
|
13
|
+
@timestamp_raw = timestamp
|
14
|
+
@services_raw = services
|
15
|
+
@address_raw = address
|
16
|
+
@port_raw = port
|
17
|
+
end
|
18
|
+
|
19
|
+
def timestamp
|
20
|
+
@timestamp ||= @timestamp_raw.unpack('L')[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
def services
|
24
|
+
@services ||= @services_raw.unpack('Q')[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
def address
|
28
|
+
return @address if @address
|
29
|
+
address = @address_raw.unpack('H*')[0]
|
30
|
+
if address[0..11] == "000000000000" # IPv4 address
|
31
|
+
address = address[12..-1]
|
32
|
+
@address = address.each_char.each_slice(2).map{|e| e.join.to_i(16)}.join('.')
|
33
|
+
@address_version = 4
|
34
|
+
else
|
35
|
+
@address = address.each_char.each_slice(4).map{|e| e.join}.join(':')
|
36
|
+
@address_version = 6
|
37
|
+
end
|
38
|
+
@address
|
39
|
+
end
|
40
|
+
|
41
|
+
def port
|
42
|
+
@port ||= @port_raw.unpack('S')[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
def address_with_port
|
46
|
+
return "#{@address}:#{@port}" if @address_version == 4
|
47
|
+
"[#{@address}]:#{@port}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def raw
|
51
|
+
@timestamp_raw + @services_raw + @address_raw + @port_raw
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'digest/sha2'
|
2
|
+
require 'cryptocoin/protocol/message'
|
3
|
+
|
4
|
+
module Cryptocoin
|
5
|
+
module Protocol
|
6
|
+
class Packet
|
7
|
+
attr_reader :message, :network
|
8
|
+
|
9
|
+
def self.parse_from_raw(raw)
|
10
|
+
magic = raw[0..4]
|
11
|
+
command = raw[5..16]
|
12
|
+
payload_length = raw[17..20]
|
13
|
+
payload_checksum = raw[21..24]
|
14
|
+
payload = raw[25..-1]
|
15
|
+
message = Cryptocoin::Protocol::Message.parse(command, payload)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse_from_io
|
19
|
+
magic = io.read(4)
|
20
|
+
command = io.read(12)
|
21
|
+
payload_length = io.read(4)
|
22
|
+
payload_checksum = io.read(4)
|
23
|
+
payload = io.read
|
24
|
+
message = Cryptocoin::Protocol::Message.parse(command, payload)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(magic, command, payload_length, payload_checksum, message, network)
|
28
|
+
@magic_raw = magic
|
29
|
+
@command_raw = command
|
30
|
+
@payload_length_raw = payload_length
|
31
|
+
@payload_checksum_raw = payload_checksum
|
32
|
+
@message = message
|
33
|
+
@network = network
|
34
|
+
end
|
35
|
+
|
36
|
+
def magic
|
37
|
+
@magic_raw.unpack('L')[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def command
|
41
|
+
@command_raw.unpack('a*')[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def payload_length
|
45
|
+
@payload_length_raw.unpack('L')[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
def payload_checksum
|
49
|
+
@payload_checksum_raw.unpack('L')[0]
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid?
|
53
|
+
valid_checksum and valid_magic and valid_message
|
54
|
+
end
|
55
|
+
|
56
|
+
def raw
|
57
|
+
@magic_raw + @command_raw + @payload_length_raw + @payload_checksum_raw + @message.raw
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def valid_checksum
|
62
|
+
Cryptocoin::Digest.new(@message.raw, :binary).sha256[0..4] == @payload_checksum_raw
|
63
|
+
end
|
64
|
+
|
65
|
+
def valid_magic
|
66
|
+
magic == network.magic
|
67
|
+
end
|
68
|
+
|
69
|
+
def valid_message
|
70
|
+
@message.valid?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
module Protocol
|
3
|
+
class VarLenInt
|
4
|
+
# https://github.com/andrew12/bitcoin-ruby/blob/master/lib/bitcoin.rb#L132
|
5
|
+
# TODO: test this implementation
|
6
|
+
def self.from_int(i)
|
7
|
+
if i < -0xffffffffffffffff
|
8
|
+
return ArgumentError, "Unrepresentable"
|
9
|
+
elsif i < 0
|
10
|
+
top_32 = ((-i) & 0xffffffff00000000) >> 32
|
11
|
+
btm_32 = (-i) & 0x00000000ffffffff
|
12
|
+
return self.new([0xff, top_32, btm_32].pack("CVV"))
|
13
|
+
elsif i <= 0xfc
|
14
|
+
return self.new([i].pack('C'))
|
15
|
+
elsif i <= 0xffff
|
16
|
+
return self.new([0xfd, i].pack("Cv"))
|
17
|
+
elsif i <= 0xffffffff
|
18
|
+
return self.new([0xfe, i].pack("CV"))
|
19
|
+
else
|
20
|
+
return ArgumentError, "Unrepresentable"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_from_io(io)
|
25
|
+
i = io.read(1)
|
26
|
+
j = i.unpack('C')[0]
|
27
|
+
case j
|
28
|
+
when 0xfd
|
29
|
+
self.new(i + io.read(2))
|
30
|
+
when 0xfe
|
31
|
+
self.new(i + io.read(4))
|
32
|
+
when 0xff
|
33
|
+
self.new(i + io.read(8))
|
34
|
+
else
|
35
|
+
puts "Something: #{i}"
|
36
|
+
self.new(i)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(raw)
|
41
|
+
@head_raw = raw[0]
|
42
|
+
@head = @head_raw.unpack('C')[0]
|
43
|
+
@body = case @head
|
44
|
+
when 0xfd
|
45
|
+
@raw_i = raw[1..3]
|
46
|
+
@raw_i.unpack('v')[0]
|
47
|
+
when 0xfe
|
48
|
+
@raw_i = raw[1..5]
|
49
|
+
@raw_i.unpack('V')[0]
|
50
|
+
when 0xff
|
51
|
+
@raw_i = raw[1..9]
|
52
|
+
@raw_i.unpack('Q')[0]
|
53
|
+
else
|
54
|
+
@raw_i = @head_raw
|
55
|
+
@head
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_i
|
60
|
+
@body
|
61
|
+
end
|
62
|
+
|
63
|
+
def head
|
64
|
+
@head
|
65
|
+
end
|
66
|
+
|
67
|
+
def body_raw
|
68
|
+
@raw_i
|
69
|
+
end
|
70
|
+
|
71
|
+
def body
|
72
|
+
@body
|
73
|
+
end
|
74
|
+
|
75
|
+
def raw
|
76
|
+
@head_raw + (@raw_i == @head_raw ? '' : @raw_i)
|
77
|
+
end
|
78
|
+
|
79
|
+
def method_missing(name, *args, &block)
|
80
|
+
ret = body.send(name, *args, &block)
|
81
|
+
ret
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'cryptocoin/protocol/var_len_int'
|
2
|
+
|
3
|
+
module Cryptocoin
|
4
|
+
module Protocol
|
5
|
+
class VarLenStr < String
|
6
|
+
def initialize(raw)
|
7
|
+
@size = Cryptocoin::Protocol::VarLenInt.new(raw)
|
8
|
+
@str = raw.read(@size)
|
9
|
+
end
|
10
|
+
def size
|
11
|
+
@size
|
12
|
+
end
|
13
|
+
def to_s
|
14
|
+
@str
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|