cryptocoin 0.0.1b

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +85 -0
  7. data/Rakefile +2 -0
  8. data/cryptocoin.gemspec +24 -0
  9. data/lib/cryptocoin/core_ext/integer.rb +24 -0
  10. data/lib/cryptocoin/core_ext/string.rb +30 -0
  11. data/lib/cryptocoin/digest.rb +36 -0
  12. data/lib/cryptocoin/merkle_tree.rb +78 -0
  13. data/lib/cryptocoin/network/bitcoin.rb +9 -0
  14. data/lib/cryptocoin/network/dogecoin.rb +9 -0
  15. data/lib/cryptocoin/network/litecoin.rb +9 -0
  16. data/lib/cryptocoin/network.rb +53 -0
  17. data/lib/cryptocoin/protocol/block_header.rb +58 -0
  18. data/lib/cryptocoin/protocol/inventory_vector.rb +28 -0
  19. data/lib/cryptocoin/protocol/message/addr.rb +29 -0
  20. data/lib/cryptocoin/protocol/message/alert.rb +0 -0
  21. data/lib/cryptocoin/protocol/message/block.rb +13 -0
  22. data/lib/cryptocoin/protocol/message/getaddr.rb +17 -0
  23. data/lib/cryptocoin/protocol/message/getblocks.rb +44 -0
  24. data/lib/cryptocoin/protocol/message/getdata.rb +31 -0
  25. data/lib/cryptocoin/protocol/message/getheaders.rb +44 -0
  26. data/lib/cryptocoin/protocol/message/headers.rb +30 -0
  27. data/lib/cryptocoin/protocol/message/inv.rb +31 -0
  28. data/lib/cryptocoin/protocol/message/mempool.rb +16 -0
  29. data/lib/cryptocoin/protocol/message/notfound.rb +31 -0
  30. data/lib/cryptocoin/protocol/message/ping.rb +24 -0
  31. data/lib/cryptocoin/protocol/message/pong.rb +24 -0
  32. data/lib/cryptocoin/protocol/message/reject.rb +54 -0
  33. data/lib/cryptocoin/protocol/message/tx.rb +11 -0
  34. data/lib/cryptocoin/protocol/message/verack.rb +16 -0
  35. data/lib/cryptocoin/protocol/message/version.rb +59 -0
  36. data/lib/cryptocoin/protocol/message.rb +27 -0
  37. data/lib/cryptocoin/protocol/net_addr.rb +55 -0
  38. data/lib/cryptocoin/protocol/packet.rb +74 -0
  39. data/lib/cryptocoin/protocol/var_len_int.rb +85 -0
  40. data/lib/cryptocoin/protocol/var_len_str.rb +18 -0
  41. data/lib/cryptocoin/protocol.rb +8 -0
  42. data/lib/cryptocoin/script/op_code/constants.rb +157 -0
  43. data/lib/cryptocoin/script/op_code/functions.rb +515 -0
  44. data/lib/cryptocoin/script/op_code.rb +59 -0
  45. data/lib/cryptocoin/script.rb +234 -0
  46. data/lib/cryptocoin/structure/address.rb +64 -0
  47. data/lib/cryptocoin/structure/block.rb +109 -0
  48. data/lib/cryptocoin/structure/key_pair.rb +57 -0
  49. data/lib/cryptocoin/structure/merkle_branch.rb +37 -0
  50. data/lib/cryptocoin/structure/transaction/input.rb +80 -0
  51. data/lib/cryptocoin/structure/transaction/output.rb +49 -0
  52. data/lib/cryptocoin/structure/transaction.rb +94 -0
  53. data/lib/cryptocoin/version.rb +3 -0
  54. data/lib/cryptocoin.rb +29 -0
  55. data/spec/script_spec.rb +42 -0
  56. data/spec/spec_helper.rb +20 -0
  57. metadata +145 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ae2ad988c5dfd3d449144149aa36ef902ed9a221
4
+ data.tar.gz: 19dba874b95a3fd7d475f9ff5efe9b3b0c95690f
5
+ SHA512:
6
+ metadata.gz: 79067c43a159c2136d7c2f020d365b6e0d135ae9dcd2de0629b2c31705fd7f8b36bed213fdcd9bca1e457d5199673224fcaaed30017691f96c34794cb3e42520
7
+ data.tar.gz: 20bc7fb25bb18b2020b80904724c26fcbdb3b6557eec2586721425ad45d356d7614f90166ad1055976523d4e516cfec1ee77abd49a64bf25e549746ea1c9c4a8
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cryptocoin.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Joshua Smock
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Cryptocoin
2
+
3
+ Cryptocoin is a library for processing information from a Bitcoin-based cryptocoin network and wrapping that data in a useful and Ruby-like manner. Although based off of `bitcoin-ruby` in concept, it deviates largely due to its philosophy in implementations; rather than trying to do everything, `cryptocoin` just provides wrappers around cryptocoin structures such as a block or merkle tree. Due to this difference, it cannot do certain features such as block validation, as block validation requires information beyond the basic structure (multiple transactions).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'cryptocoin'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install cryptocoin
18
+
19
+ ## Notes
20
+
21
+ ### Usage Notes
22
+
23
+ Since Ruby uses the method `hash` as an internal descriptor for objects, in general, the result of a hashing function such as `RIPEMD160` or `SHA256` will be referred to as a digest.
24
+
25
+ ### Library Notes
26
+
27
+ Cryptocoin will only work with cryptocurrencies that follow the Bitcoin protocol.
28
+
29
+ This library does not perform validation of blocks or transactions; it only acts as a data parser. The reason for this is that validation is inherently coupled with a storage solution, such as an SQL database, for certain validation rules and the purpose of this library is only to parse data. For a library that performs validation, see `cryptocoin-validator`.
30
+
31
+ For importing from a blockchain data file, see `cryptocoin-import`.
32
+
33
+ ## Sample Usage
34
+
35
+ ### Generate a new key pair
36
+
37
+ ```
38
+ require 'cryptocoin'
39
+ key_pair = Cryptocoin::Structure::KeyPair.generate
40
+ public_address = key_pair.public_key.to_address.to_s
41
+ private_address = key_pair.private_key.to_address.to_s
42
+ ```
43
+
44
+ (Note: The reason `to_s` is called is that `to_address` creates a new `Cryptocoin::Structure::Address` instance which can then be turned into a string via `to_s`.)
45
+
46
+ ### Create a new Script
47
+
48
+ ```
49
+ require 'cryptocoin'
50
+ script = Cryptocoin::Script.from_s("OP_1")
51
+ script.parse! #=> true
52
+ ```
53
+
54
+ ## What's built with `cryptocoin`?
55
+
56
+ Officially supported (coming soon!):
57
+ * `cryptocoin-validator`: a block and transaction validator based off of Bitcoin protocol validation rules. Works with SHA256 (Bitcoin) and Scrypt (Litecoin) based currencies
58
+ * `cryptocoin-import`: a blockchain data file importer. Reads a blockchain file, i.e. `blk00001.dat`, and imports it into the database.
59
+
60
+ ## Thanks
61
+
62
+ A lot of this code couldn't be possible without `bitcoin-ruby`, the library that started this idea. Also a huge help were the [Bitcoin wiki](https://www.bitcoin.it) and the current Bitcoin source code v0.9. A special thanks to the `bitcoinj` library for its Script directive processing, especially for OP_CHECKSIG.
63
+
64
+ ## Contributing
65
+
66
+ ### What's missing?
67
+
68
+ * Support for BIP 0037, titled, "Connection Bloom Filtering"
69
+ * Support for other cryptocurrencies besides Litecoin, Bitcoin, and Dogecoin
70
+
71
+ ### How to Contribute
72
+
73
+ If you find a bug or would like to add a new feature, fork the library and create a PR based on your changes! Keep the code consistent with my existing code, and follow similar conventions to the existing ones.
74
+
75
+ When creating a PR that adds a new feature, make sure you justify its utility to the base library, with some use cases in the PR or in a gist. Ideally the library will be kept as slim as possible, and additonal non-essential functionality for data parsing will be added to other libraries.
76
+
77
+ One area I would really like help with is adding various networks to the library, as I only included a handful (Bitcoin, Litecoin, Dogecoin). If you're knowledgeable with a different cryptocoin and want to add it to the library, fork, create, and request to pull it! I'd love to have more than just three!
78
+
79
+ #### Instructions for forking
80
+
81
+ 1. Fork it ( https://github.com/joshuasmock/cryptocoin/fork )
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cryptocoin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cryptocoin"
8
+ spec.version = Cryptocoin::VERSION
9
+ spec.authors = ["Joshua Smock"]
10
+ spec.email = ["joshua.smock@gmail.com"]
11
+ spec.summary = %q{Cryptocoin is a library for interfacing with Bitcoin and Bitcoin-like coins}
12
+ spec.description = %q{Cryptocoin is a library for processing messages and information from a cryptocoin network, such as a packet of information, and creating useful wrappers for such data.}
13
+ spec.homepage = "https://github.com/joshuasmock/cryptocoin"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,24 @@
1
+ class Integer
2
+ def to_bool
3
+ !self.zero?
4
+ end
5
+
6
+ def to_openssl_bn
7
+ require 'openssl'
8
+ s = OpenSSL::BN.new(self.to_s).to_s(0)
9
+ s = s[s.length-1..-1]
10
+ s
11
+ end
12
+
13
+ def to_base58
14
+ alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
15
+ encoded = ''
16
+ i = self
17
+
18
+ while i > 0
19
+ i, rem = i.divmod(58)
20
+ encoded = alphabet[rem] + encoded
21
+ end
22
+ encoded
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ require 'cryptocoin/core_ext/integer'
2
+
3
+ class String
4
+ def to_openssl_bn_int
5
+ require 'openssl'
6
+ OpenSSL::BN.new([self.bytesize].pack('N') + self.reverse, 0).to_i
7
+ end
8
+
9
+ # Returns the integer value from a base58 encoded string
10
+ def from_base58
11
+ return nil if self.match(/[0OIl]/)
12
+ alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
13
+ j = 0
14
+
15
+ self.reverse.each_char.with_index do |c, i|
16
+ j += alphabet.index(c) * (58**i)
17
+ end
18
+ j
19
+ end
20
+
21
+ def reverse_every(n)
22
+ self.each_char.each_slice(n).reverse_each.reduce(''){|r,i| r+=i.join}
23
+ end
24
+
25
+ def encode_to_base58
26
+ return nil if self.to_i(16) == 0
27
+ i = (self.match(/^([0]+)/) ? $1 : '').size / 2
28
+ ('1'*i) + self.to_i(16).to_base58
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ require 'digest/sha2'
2
+ require 'digest/rmd160'
3
+
4
+ module Cryptocoin
5
+ class Digest
6
+ def initialize(str, encoding)
7
+ return false if ![:string, :binary].include?(encoding)
8
+ @plaintext = str.to_s
9
+ @encoding = encoding
10
+ end
11
+
12
+ def sha256
13
+ if @encoding == :binary
14
+ ::Digest::SHA256.hexdigest(@plaintext)
15
+ elsif @encoding == :string
16
+ ::Digest::SHA256.hexdigest([@plaintext].pack('H*'))
17
+ end
18
+ end
19
+
20
+ def double_sha256
21
+ if @encoding == :binary
22
+ ::Digest::SHA256.hexdigest(::Digest::SHA256.digest(@plaintext))
23
+ elsif @encoding == :string
24
+ ::Digest::SHA256.hexdigest(::Digest::SHA256.digest([@plaintext].pack('H*')))
25
+ end
26
+ end
27
+
28
+ def hash160
29
+ if @encoding == :binary
30
+ ::Digest::RMD160.hexdigest(::Digest::SHA256.digest(@plaintext))
31
+ elsif @encoding == :string
32
+ ::Digest::RMD160.hexdigest(::Digest::SHA256.digest([@plaintext].pack('H*')))
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,78 @@
1
+ require 'cryptocoin/digest'
2
+ require 'cryptocoin/core_ext/string'
3
+
4
+ module Cryptocoin
5
+ class MerkleTree
6
+ def initialize(arr, hashed=true)
7
+ # Build the merkle tree!
8
+ @children = []
9
+ create_tree(arr)
10
+ end
11
+
12
+ def root
13
+ if @children.first.children.count == 1 # only child has one child, which means it's got one leaf
14
+ @children.first.children.first.digest
15
+ else
16
+ @children.first.digest
17
+ end
18
+ end
19
+
20
+ def children
21
+ @children
22
+ end
23
+
24
+ # Each child is either the product of two children or one/two leaves
25
+ class Child
26
+ attr_reader :children
27
+
28
+ def initialize(children)
29
+ @children = children
30
+ end
31
+
32
+ def digest
33
+ if @children.count == 1
34
+ return @children.first.digest if @children.first.initially_hashed?
35
+ @digest ||= Cryptocoin::Digest.new(@children.first.digest.reverse_every(2), :string).double_sha256.reverse_every(2)
36
+ else
37
+ @digest ||= Cryptocoin::Digest.new((@children.last.digest + @children.first.digest).reverse_every(2), :string).double_sha256.reverse_every(2)
38
+ end
39
+ end
40
+
41
+ def initially_hashed?
42
+ false
43
+ end
44
+ end
45
+
46
+ # The base element of a merkle tree
47
+ class Leaf
48
+ attr_reader :value
49
+ def initialize(val, hashed=false)
50
+ @value = val
51
+ @hashed = hashed
52
+ end
53
+
54
+ def digest
55
+ return @value if initially_hashed?
56
+ Cryptocoin::Digest.new(@value, :string).double_sha256.reverse_every(2)
57
+ end
58
+
59
+ def initially_hashed?
60
+ !!@hashed
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def create_tree(arr)
67
+ return @children = [Child.new([Leaf.new(arr[0], truee)])] if arr.length == 1
68
+ children = arr.map{|e| Leaf.new(e, true)}
69
+ until children.length == 1
70
+ children.push(children.last) if children.length % 2 == 1
71
+ children = children.each_slice(2).map {|a,b|
72
+ Child.new([a,b])
73
+ }
74
+ end
75
+ @children = children
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,9 @@
1
+ module Cryptocoin
2
+ class Network
3
+ Bitcoin = self.new
4
+ Bitcoin.magic_head_raw = "\xF9\xBE\xB4\xD9"
5
+ Bitcoin.hash160_version_raw = "\x00"
6
+ Bitcoin.p2sh_version_raw = "\x05"
7
+ Bitcoin.private_key_version_raw = "\x80"
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Cryptocoin
2
+ class Network
3
+ Dogecoin = self.new
4
+ Dogecoin.magic_head_raw = "\xc0\xc0\xc0\xc0"
5
+ Dogecoin.hash160_version_raw = "\x1e"
6
+ Dogecoin.p2sh_version_raw = "\x22"
7
+ Dogecoin.private_key_version_raw = "\x9e"
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Cryptocoin
2
+ class Network
3
+ Litecoin = self.new
4
+ Litecoin.magic_head_raw = "\xfb\xc0\xb6\xdb"
5
+ Litecoin.hash160_version_raw = "\x30"
6
+ Litecoin.p2sh_version_raw = "\x05"
7
+ Litecoin.private_key_version_raw = "\xb0"
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ module Cryptocoin
2
+ # Class contains protocol information like the magic_head and address types
3
+ # Does NOT contain validation information as this would require dependence on an outside source
4
+ # of information
5
+ class Network
6
+ attr_accessor :magic_head_raw, :hash160_version_raw, :p2sh_version_raw, :private_key_version_raw, :protocol_version_raw
7
+
8
+ def magic_head
9
+ @magic_head ||= @magic_head_raw.unpack('H*')[0]
10
+ end
11
+
12
+ def magic_head=(magic_head)
13
+ @magic_head_raw = [magic_head].pack('H*')
14
+ @magic_head = nil
15
+ end
16
+
17
+ def hash160_version
18
+ @hash160_version ||= @hash160_version_raw.unpack('H*')[0]
19
+ end
20
+
21
+ def hash160_version=(hash160_version)
22
+ @hash160_version_raw = [hash160_version].pack('H*')
23
+ @hash160_version = nil
24
+ end
25
+
26
+ def p2sh_version
27
+ @p2sh_version ||= @p2sh_version_raw.unpack('H*')[0]
28
+ end
29
+
30
+ def p2sh_version=(p2sh_version)
31
+ @p2sh_version_raw = [p2sh_version].pack('H*')
32
+ @p2sh_version = nil
33
+ end
34
+
35
+ def private_key_version
36
+ @private_key_version_raw.unpack('H*')[0]
37
+ end
38
+
39
+ def private_key_version=(private_key_version)
40
+ @private_key_version_raw = [private_key_version].pack('H*')
41
+ @private_key_version = nil
42
+ end
43
+
44
+ def protocol_version
45
+ @protocol_version ||= @protocol_version_raw.unpack('H*')[0]
46
+ end
47
+
48
+ def protocol_version=(protocol_version)
49
+ @protocol_version_raw = [protocol_version].pack('H*')
50
+ @protocol_version = nil
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,58 @@
1
+ require 'cryptocoin/protocol/var_len_int'
2
+
3
+ module Cryptocoin
4
+ module Protocol
5
+ class BlockHeader
6
+ attr_reader :transaction_count
7
+
8
+ def self.parse_from_raw(raw)
9
+ version = raw[0..3]
10
+ previous_block_digest = raw[4..35]
11
+ merkle_root_digest = raw[36..67]
12
+ timestamp = raw[68..71]
13
+ bits = raw[72..75]
14
+ nonce = raw[76..79]
15
+ tx_count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(raw[80..-1])
16
+ self.new(version, previous_block_digest, merkle_root_digest, timestamp, bits, nonce, tx_count)
17
+ end
18
+
19
+ def initialize(version, previous_block_digest, merkle_root_digest, timestamp, bits, nonce, tx_count)
20
+ @version_raw = version
21
+ @previous_block_digest_raw = previous_block_digest
22
+ @merkle_root_digest_raw = merkle_root_digest
23
+ @timestamp_raw = timestamp
24
+ @bits_raw = bits
25
+ @nonce_raw = nonce
26
+ @transaction_count = tx_count
27
+ end
28
+
29
+ def version
30
+ @version ||= @version_raw.unpack('L')[0]
31
+ end
32
+
33
+ def previous_block_digest
34
+ @previous_block_digest ||= @previous_block_digest_raw.unpack('H*')[0]
35
+ end
36
+
37
+ def merkle_root_digest
38
+ @merkle_root_digest_raw ||= @merkle_root_digest_raw.unpack('H*')[0]
39
+ end
40
+
41
+ def timestamp
42
+ @timestamp ||= @timestamp_raw.unpack('L')[0]
43
+ end
44
+
45
+ def bits
46
+ @bits ||= @bits_raw.unpack('L')[0]
47
+ end
48
+
49
+ def nonce
50
+ @nonce ||= @nonce_raw.unpack('L')[0]
51
+ end
52
+
53
+ def raw
54
+ @version_raw + @previous_block_digest_raw + @merkle_root_digest_raw + @timestamp_raw + @bits_raw + @nonce_raw + @transaction_count.raw
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,28 @@
1
+ module Cryptocoin
2
+ module Protocol
3
+ class InventoryVector
4
+ def self.parse_from_raw(raw)
5
+ type = raw[0..3]
6
+ digest = raw[4..-1]
7
+ self.new(type, digest)
8
+ end
9
+
10
+ def initialize(type, digest)
11
+ @type_raw = type
12
+ @digest_raw = digest
13
+ end
14
+
15
+ def type
16
+ @type_raw.unpack('L')[0]
17
+ end
18
+
19
+ def digest
20
+ @digest_raw.unpack('H*')[0]
21
+ end
22
+
23
+ def raw
24
+ @type_raw + @digest_raw
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require 'cryptocoin/protocol/var_len_int'
2
+ require 'cryptocoin/protocol/net_addr'
3
+
4
+ module Cryptocoin
5
+ module Protocol
6
+ class Message
7
+ class Addr
8
+ attr_reader :count, :addresses
9
+ def parse_from_raw(payload)
10
+ count = Cryptocoin::Protocol::VarLenInt.parse_from_raw(payload)
11
+ addresses = []
12
+ count.times do
13
+ addresses.push(Cryptocoin::Protocol::NetAddr.parse_from_raw(payload[@count.raw.bytesize + 30*@addresses.count]))
14
+ end
15
+ self.new(count, addresses)
16
+ end
17
+
18
+ def initialize(count, addresses)
19
+ @count = count
20
+ @addresses = addresses
21
+ end
22
+
23
+ def raw
24
+ @count.raw + @addresses.map{|e| e.raw}.join
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
File without changes
@@ -0,0 +1,13 @@
1
+ require 'cryptocoin/structure/block'
2
+
3
+ module Cryptocoin
4
+ module Protocol
5
+ class Message
6
+ class Block
7
+ def initialize(payload)
8
+ Cryptocoin::Structure::Block.parse_from_raw(payload)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Cryptocoin
2
+ module Protocol
3
+ class Message
4
+ class Getaddr
5
+ def parse_from_raw(payload)
6
+ # https://en.bitcoin.it/wiki/Protocol_specification#getaddr
7
+ # This message has no payload
8
+ self.new
9
+ end
10
+
11
+ def raw
12
+ nil
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ module Cryptocoin
2
+ module Protocol
3
+ class Message
4
+ class Getblocks
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,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 Getdata
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