cryptocoin 0.0.1b

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 (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