katapaty 0.3.1 → 0.3.2
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 +4 -4
- data/katapaty.gemspec +4 -1
- data/lib/katapaty/tx_decode.rb +121 -0
- data/lib/katapaty/version.rb +1 -1
- data/lib/katapaty.rb +1 -0
- metadata +49 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc8613cff7b2c9422344e372d3caf4f74a8a9147
|
4
|
+
data.tar.gz: b6448ed8b21e0ee7043c87fc68287799842b8c3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c025e09a945d8295ddfb860f4c92b5198625bf61bbf0829e60dc2affc3f200068f1c9cdd5227e6e8f1220f52f87470be8c739eeedc96312d61bfb1bccecdd5ec
|
7
|
+
data.tar.gz: 4d772e3b257ab68524b8c74c285a4a7b98af921f9fbf30ffee11a40b4498fff89bd5eeaffdb39c2dccdc55068b855aabbc90b8b7b3f8b4a8303c9947aa1dac03
|
data/katapaty.gemspec
CHANGED
@@ -24,6 +24,9 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
26
|
|
27
|
-
spec.add_dependency "json"
|
27
|
+
spec.add_dependency "json", "~> 2.1.0"
|
28
28
|
spec.add_dependency "rest-client", "~> 1.8.0"
|
29
|
+
spec.add_dependency "bitcoin-ruby", "0.0.15"
|
30
|
+
spec.add_dependency "ruby-rc4", "~> 0.1.5"
|
31
|
+
spec.add_dependency "ffi", "~> 1.9.21"
|
29
32
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
##
|
2
|
+
# Author: https://github.com/brighton36/counterparty_ruby/blob/master/lib/counterparty/tx_decode.rb
|
3
|
+
# encoding: utf-8
|
4
|
+
# Inspriration heavily lifted from:
|
5
|
+
# - https://github.com/tokenly/counterparty-transaction-parser
|
6
|
+
##
|
7
|
+
module Katapaty
|
8
|
+
class TxDecode
|
9
|
+
class UndefinedBehavior < StandardError; end
|
10
|
+
class InvalidOpReturn < StandardError; end
|
11
|
+
class InvalidOutput < StandardError; end
|
12
|
+
class MultisigUnsupported < StandardError; end
|
13
|
+
|
14
|
+
DEFAULT_PREFIX = 'CNTRPRTY'
|
15
|
+
|
16
|
+
OP_RETURN_PARTS = /^OP_RETURN ([a-z0-9]+)$/
|
17
|
+
P2PKH_PARTS = /^OP_DUP OP_HASH160 ([a-z0-9]+) OP_EQUALVERIFY OP_CHECKSIG$/
|
18
|
+
OP_MULTISIG_PARTS = /^[12] ([a-z0-9 ]+) ([23]) OP_CHECKMULTISIG$/
|
19
|
+
|
20
|
+
attr_accessor :sender_addr, :receiver_addr, :decrypt_key, :data, :prefix
|
21
|
+
|
22
|
+
def initialize(tx, options = {})
|
23
|
+
@prefix = options[:prefix] || DEFAULT_PREFIX
|
24
|
+
@decrypt_key = options[:decrypt_key] || [tx.inputs[0].prev_out.reverse_hth].pack('H*')
|
25
|
+
|
26
|
+
parse! (tx.respond_to? :outputs) ?
|
27
|
+
tx.outputs.collect{|out| out.parsed_script.to_string } : tx
|
28
|
+
end
|
29
|
+
|
30
|
+
def decrypt(chunk)
|
31
|
+
RC4.new(decrypt_key).decrypt chunk
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def prefixed?(data, offset = 1)
|
37
|
+
data[offset...(prefix.length+offset)] == prefix
|
38
|
+
end
|
39
|
+
|
40
|
+
# This determines if the supplied operation is a non-data
|
41
|
+
def is_non_prefixed_p2pkh?(op)
|
42
|
+
P2PKH_PARTS.match(op) && !prefixed?(decrypt([$1].pack('H*')))
|
43
|
+
end
|
44
|
+
|
45
|
+
def hash160_from_p2pkh(op)
|
46
|
+
Bitcoin.hash160_to_address $1 if P2PKH_PARTS.match op
|
47
|
+
end
|
48
|
+
|
49
|
+
# Note that this isn't exactly the way counterparty parses the transactions.
|
50
|
+
# But , it reads cleaner, and worked on every transaction I could find.
|
51
|
+
# Mostly the difference is that the counterparty version is a loop that
|
52
|
+
# collects P2PKH's anywhere in the outputs, whereas this block takes a sender
|
53
|
+
# or receiver address from the top and bottom only
|
54
|
+
def parse!(outputs)
|
55
|
+
return if @data
|
56
|
+
|
57
|
+
# So typically, the first output is a P2PKH with the receiver address:
|
58
|
+
@receiver_addr = hash160_from_p2pkh outputs.shift if is_non_prefixed_p2pkh? outputs.first
|
59
|
+
|
60
|
+
# Parse the sender address:
|
61
|
+
@sender_addr = hash160_from_p2pkh outputs.pop if is_non_prefixed_p2pkh? outputs.last
|
62
|
+
|
63
|
+
@data = outputs.collect{|out|
|
64
|
+
# This weirdo line will send the regex matches to the operation handler
|
65
|
+
# that matches the line
|
66
|
+
send (case out
|
67
|
+
when OP_RETURN_PARTS then :data_from_opreturn
|
68
|
+
when P2PKH_PARTS then :data_from_opchecksig
|
69
|
+
when OP_MULTISIG_PARTS then :data_from_opcheckmultisig
|
70
|
+
else raise InvalidOutput
|
71
|
+
end), *$~.to_a[1..-1]
|
72
|
+
}.compact.join
|
73
|
+
end
|
74
|
+
|
75
|
+
def data_from_opreturn(data)
|
76
|
+
chunk = [data].pack('H*')
|
77
|
+
|
78
|
+
raise InvalidOpReturn if chunk.nil?
|
79
|
+
|
80
|
+
data = decrypt chunk
|
81
|
+
|
82
|
+
raise InvalidOpReturn unless prefixed?(data,0)
|
83
|
+
|
84
|
+
data[prefix.length..-1]
|
85
|
+
end
|
86
|
+
|
87
|
+
def data_from_opchecksig(pubkeyhash_text)
|
88
|
+
chunk = decrypt [pubkeyhash_text].pack('H*')
|
89
|
+
|
90
|
+
# This should get picked up by the sender and receiver pop/shift in parse!
|
91
|
+
# However, the counterparty lib would parse these obtuse addresses typically
|
92
|
+
# ATM - I can't find one in the wild
|
93
|
+
raise UndefinedBehavior unless prefixed? chunk
|
94
|
+
|
95
|
+
chunk_length = chunk[0].ord
|
96
|
+
chunk[(1+prefix.length)...chunk_length+1]
|
97
|
+
end
|
98
|
+
|
99
|
+
def data_from_opcheckmultisig(pubkeys_op, n_signatures_op)
|
100
|
+
pubkeys, n_signatures = pubkeys_op.split(' '), n_signatures_op.to_i
|
101
|
+
|
102
|
+
# There's no data in the last pubkey:
|
103
|
+
chunk = pubkeys[0...-1].collect{ |pubkey|
|
104
|
+
[pubkey].pack('H*')[1...-1] # Skip sign byte and nonce byte.
|
105
|
+
}.reduce(:+)
|
106
|
+
|
107
|
+
data = decrypt chunk
|
108
|
+
|
109
|
+
# Multisig transactions will break here. I haven't actually collected enough
|
110
|
+
# of these samples yet to really test, but it seems they are typically are
|
111
|
+
# at the top of the output stack:
|
112
|
+
raise MultisigUnsupported unless prefixed? data
|
113
|
+
|
114
|
+
# Padding byte in each output (instead of just in the last one) so that
|
115
|
+
# encoding methods may be mixed. Also, it’s just not very much data.
|
116
|
+
chunk_length = data[0].ord
|
117
|
+
|
118
|
+
data[1..chunk_length][prefix.length..-1]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/katapaty/version.rb
CHANGED
data/lib/katapaty.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: katapaty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- longhoang.wkm
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: json
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 2.1.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 2.1.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rest-client
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,48 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.8.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bitcoin-ruby
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.0.15
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.0.15
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ruby-rc4
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.1.5
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.1.5
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: ffi
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.9.21
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.9.21
|
83
125
|
description:
|
84
126
|
email:
|
85
127
|
- longhoang@wakumo.vn
|
@@ -100,6 +142,7 @@ files:
|
|
100
142
|
- lib/katapaty.rb
|
101
143
|
- lib/katapaty/configuration.rb
|
102
144
|
- lib/katapaty/errors.rb
|
145
|
+
- lib/katapaty/tx_decode.rb
|
103
146
|
- lib/katapaty/version.rb
|
104
147
|
homepage: https://github.com/longhoangwkm/katapaty
|
105
148
|
licenses:
|