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
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
data/Gemfile
ADDED
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
data/cryptocoin.gemspec
ADDED
@@ -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,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,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
|