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