tapyrus 0.1.0 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -15
  3. data/exe/tapyrusrbd +2 -2
  4. data/lib/openassets/util.rb +2 -4
  5. data/lib/schnorr.rb +83 -0
  6. data/lib/schnorr/signature.rb +38 -0
  7. data/lib/tapyrus.rb +11 -18
  8. data/lib/tapyrus/block.rb +3 -38
  9. data/lib/tapyrus/block_header.rb +70 -41
  10. data/lib/tapyrus/chain_params.rb +13 -36
  11. data/lib/tapyrus/chainparams/{regtest.yml → dev.yml} +10 -19
  12. data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -19
  13. data/lib/tapyrus/constants.rb +12 -34
  14. data/lib/tapyrus/errors.rb +17 -0
  15. data/lib/tapyrus/ext.rb +5 -0
  16. data/lib/tapyrus/ext/ecdsa.rb +39 -0
  17. data/lib/tapyrus/ext/json_parser.rb +47 -0
  18. data/lib/tapyrus/ext_key.rb +42 -23
  19. data/lib/tapyrus/key.rb +47 -40
  20. data/lib/tapyrus/message.rb +2 -2
  21. data/lib/tapyrus/message/base.rb +1 -0
  22. data/lib/tapyrus/message/block.rb +4 -4
  23. data/lib/tapyrus/message/cmpct_block.rb +3 -5
  24. data/lib/tapyrus/message/header_and_short_ids.rb +1 -1
  25. data/lib/tapyrus/message/headers.rb +1 -1
  26. data/lib/tapyrus/message/merkle_block.rb +1 -1
  27. data/lib/tapyrus/message/tx.rb +2 -2
  28. data/lib/tapyrus/network/peer.rb +1 -15
  29. data/lib/tapyrus/node/cli.rb +15 -11
  30. data/lib/tapyrus/node/configuration.rb +1 -1
  31. data/lib/tapyrus/node/spv.rb +1 -1
  32. data/lib/tapyrus/opcodes.rb +5 -0
  33. data/lib/tapyrus/out_point.rb +1 -1
  34. data/lib/tapyrus/rpc/request_handler.rb +7 -6
  35. data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
  36. data/lib/tapyrus/script/color.rb +79 -0
  37. data/lib/tapyrus/script/multisig.rb +0 -27
  38. data/lib/tapyrus/script/script.rb +74 -89
  39. data/lib/tapyrus/script/script_error.rb +8 -14
  40. data/lib/tapyrus/script/script_interpreter.rb +65 -86
  41. data/lib/tapyrus/script/tx_checker.rb +21 -5
  42. data/lib/tapyrus/secp256k1.rb +1 -0
  43. data/lib/tapyrus/secp256k1/native.rb +93 -20
  44. data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
  45. data/lib/tapyrus/secp256k1/ruby.rb +63 -54
  46. data/lib/tapyrus/store/chain_entry.rb +3 -2
  47. data/lib/tapyrus/store/db/level_db.rb +58 -0
  48. data/lib/tapyrus/store/spv_chain.rb +29 -11
  49. data/lib/tapyrus/tx.rb +18 -160
  50. data/lib/tapyrus/tx_in.rb +4 -11
  51. data/lib/tapyrus/tx_out.rb +2 -1
  52. data/lib/tapyrus/util.rb +8 -0
  53. data/lib/tapyrus/validation.rb +1 -6
  54. data/lib/tapyrus/version.rb +1 -1
  55. data/lib/tapyrus/wallet/account.rb +1 -0
  56. data/lib/tapyrus/wallet/master_key.rb +1 -0
  57. data/tapyrusrb.gemspec +3 -3
  58. metadata +44 -39
  59. data/lib/tapyrus/chainparams/testnet.yml +0 -41
  60. data/lib/tapyrus/descriptor.rb +0 -147
  61. data/lib/tapyrus/script_witness.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73863e0b35030aee45baa96661f5bbd0322e78381be022d8372e620f8cd8668c
4
- data.tar.gz: 3f6378420bb9940a4829e378bb9975c67f5e5c5b61e4c5e077d85f83e0f59715
3
+ metadata.gz: 6e7f821324dfe56eb103457c17b585792e2cc250c3738f59f1665aa4a831a917
4
+ data.tar.gz: 1faa2850c7dfe07d9be35c75e3c9500e10ef39725db64fc01d88de5548894068
5
5
  SHA512:
6
- metadata.gz: 5ffa34b251d363ade9355430980d50d233c104071b15f46535fee2009b8826f4b163891e384cec997b72e2680387cd3d200b55a41c4ebda8c359fdf6f965f091
7
- data.tar.gz: c3860a9b13c2f43ef55b47cb985eb9467d5c4fdf9f1436b6c0e97b9a1b04a2ecdcd726e0103baa5ccd302753cc460f0240c0cd76c32cc08347e46e997e0ec7d6
6
+ metadata.gz: 3299a042ff5f3fa919d4732c1c7c9288cef3bdb213267171d7fa733b53929479b83abb333be1820304fbb593cda742fd8240d8589424536a044901e92cf96823
7
+ data.tar.gz: c579e85d346cb81290e5854c303147f32dbe1df3049f4190f05af1fded387aaf7cf7cc4170761fa9eaf409c174b7b37f9f3031193c442567bc95e5d8b1b02e2f
data/README.md CHANGED
@@ -12,7 +12,7 @@ Tapyrusrb supports following feature:
12
12
  * Tapyrus script interpreter
13
13
  * De/serialization of Tapyrus protocol network messages
14
14
  * De/serialization of blocks and transactions
15
- * Key generation and verification for ECDSA, including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports.
15
+ * Key generation and verification for Schnorr and ECDSA (including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports).
16
16
  * ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
17
17
  * [WIP] SPV node
18
18
  * [WIP] 0ff-chain protocol
@@ -65,29 +65,21 @@ And then add to your .rb file:
65
65
 
66
66
  The parameters of the blockchain are managed by `Tapyrus::ChainParams`. Switch chain parameters as follows:
67
67
 
68
- * mainnet
68
+ * prod
69
69
 
70
70
  ```ruby
71
- Tapyrus.chain_params = :mainnet
71
+ Tapyrus.chain_params = :prod
72
72
  ```
73
73
 
74
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/mainnet.yml.
74
+ This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/prod.yml.
75
75
 
76
- * testnet
76
+ * dev
77
77
 
78
78
  ```ruby
79
- Tapyrus.chain_params = :testnet
79
+ Tapyrus.chain_params = :dev
80
80
  ```
81
81
 
82
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/testnet.yml.
83
-
84
- * regtest
85
-
86
- ```ruby
87
- Tapyrus.chain_params = :regtest
88
- ```
89
-
90
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/regtest.yml.
82
+ This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/dev.yml.
91
83
 
92
84
  ## Contributing
93
85
 
@@ -16,11 +16,11 @@ end
16
16
 
17
17
  class Tapyrusrbd < Thor
18
18
 
19
- class_option :network, aliases: '-n', default: :mainnet
19
+ class_option :network, aliases: '-n', default: :prod
20
20
 
21
21
  desc 'start', 'start tapyrusrb daemon.'
22
22
  def start
23
- network = options['network'] ? options['network'].to_sym : :mainnet
23
+ network = options['network'] ? options['network'].to_sym : :prod
24
24
  Tapyrus.chain_params = network
25
25
  FileUtils.mkdir_p(Tapyrus.base_dir)
26
26
  execute_daemon(['start', network: network])
@@ -18,10 +18,8 @@ module OpenAssets
18
18
  end
19
19
 
20
20
  def oa_version_byte
21
- case Tapyrus.chain_params.network
22
- when 'mainnet' then OA_VERSION_BYTE
23
- when 'testnet', 'regtest' then OA_VERSION_BYTE_TESTNET
24
- end
21
+ return OA_VERSION_BYTE if Tapyrus.chain_params.prod?
22
+ return OA_VERSION_BYTE_TESTNET if Tapyrus.chain_params.dev?
25
23
  end
26
24
  end
27
25
  end
@@ -0,0 +1,83 @@
1
+ module Schnorr
2
+ autoload :Signature, 'schnorr/signature'
3
+
4
+ module_function
5
+
6
+ GROUP = ECDSA::Group::Secp256k1
7
+ ALGO16 = 'SCHNORR + SHA256'
8
+
9
+ # Generate schnorr signature.
10
+ # @param message (String) A message to be signed with binary format.
11
+ # @param private_key (Integer) The private key.
12
+ # (The number of times to add the generator point to itself to get the public key.)
13
+ # @return (Schnorr::Signature)
14
+ def sign(message, private_key)
15
+ raise 'The message must be a 32-byte array.' unless message.bytesize == 32
16
+ raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
17
+
18
+ p = GROUP.new_point(private_key)
19
+ secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length)
20
+ secret = secret + message + ALGO16
21
+ nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, '')
22
+
23
+ k0 = nonce % GROUP.order
24
+ raise 'Creation of signature failed. k is zero' if k0.zero?
25
+
26
+ r = GROUP.new_point(k0)
27
+ k = ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) == 1 ? k0 : GROUP.order - k0
28
+
29
+ e = create_challenge(r.x, p, message)
30
+
31
+ Schnorr::Signature.new(r.x, (k + e * private_key) % GROUP.order)
32
+ end
33
+
34
+ # Verifies the given {Signature} and returns true if it is valid.
35
+ # @param message (String) A message to be signed with binary format.
36
+ # @param public_key (String) The public key with binary format.
37
+ # @param signature (String) The signature with binary format.
38
+ # @return (Boolean) whether signature is valid.
39
+ def valid_sig?(message, signature, public_key)
40
+ check_sig!(message, signature, public_key)
41
+ rescue InvalidSignatureError, ECDSA::Format::DecodeError
42
+ false
43
+ end
44
+
45
+ # Verifies the given {Signature} and raises an {InvalidSignatureError} if it is invalid.
46
+ # @param message (String) A message to be signed with binary format.
47
+ # @param public_key (String) The public key with binary format.
48
+ # @param signature (String) The signature with binary format.
49
+ # @return (Boolean)
50
+ def check_sig!(message, signature, public_key)
51
+ sig = Schnorr::Signature.decode(signature)
52
+ pubkey = ECDSA::Format::PointOctetString.decode(public_key, GROUP)
53
+ field = GROUP.field
54
+
55
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is not in the field.' unless field.include?(sig.r)
56
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is not in the field.' unless field.include?(sig.s)
57
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is zero.' if sig.r.zero?
58
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is zero.' if sig.s.zero?
59
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is larger than field size.' if sig.r >= field.prime
60
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is larger than group order.' if sig.s >= GROUP.order
61
+
62
+ e = create_challenge(sig.r, pubkey, message)
63
+
64
+ r = GROUP.new_point(sig.s) + pubkey.multiply_by_scalar(e).negate
65
+
66
+ if r.infinity? || r.x != sig.r || ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) != 1
67
+ raise Schnorr::InvalidSignatureError, 'signature verification failed.'
68
+ end
69
+
70
+ true
71
+ end
72
+
73
+ # create signature digest.
74
+ # @param (Integer) x a x coordinate for R.
75
+ # @param (ECDSA::Point) p a public key.
76
+ # @return (Integer) digest e.
77
+ def create_challenge(x, p, message)
78
+ r_x = ECDSA::Format::IntegerOctetString.encode(x, GROUP.byte_length)
79
+ p_str= p.to_hex.htb
80
+ (ECDSA.normalize_digest(Digest::SHA256.digest(r_x + p_str + message), GROUP.bit_length)) % GROUP.order
81
+ end
82
+
83
+ end
@@ -0,0 +1,38 @@
1
+ module Schnorr
2
+
3
+ class InvalidSignatureError < StandardError; end
4
+
5
+ # Instances of this class represents Schnorr signatures,
6
+ # which are simply a pair of integers named `r` and `s`.
7
+ class Signature
8
+
9
+ attr_reader :r
10
+ attr_reader :s
11
+
12
+ # @param r (Integer) the value of r.
13
+ # @param s (Integer) the value of s.
14
+ def initialize(r, s)
15
+ @r, @s = r, s
16
+ r.is_a?(Integer) or raise ArgumentError, 'r is not an integer.'
17
+ s.is_a?(Integer) or raise ArgumentError, 's is not an integer.'
18
+ end
19
+
20
+ # Parse a string to a {Signature}.
21
+ # @param string (String) signature string with binary format.
22
+ # @return (Signature) signature instance.
23
+ def self.decode(string)
24
+ raise InvalidSignatureError, 'Invalid schnorr signature length.' unless string.bytesize == 64
25
+ r = string[0...32].unpack('H*').first.to_i(16)
26
+ s = string[32..-1].unpack('H*').first.to_i(16)
27
+ new(r, s)
28
+ end
29
+
30
+ # Encode signature to string.
31
+ # @return (String) encoded signature.
32
+ def encode
33
+ ECDSA::Format::IntegerOctetString.encode(r, 32) + ECDSA::Format::IntegerOctetString.encode(s, 32)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -6,14 +6,15 @@ require 'eventmachine'
6
6
  require 'ecdsa'
7
7
  require 'securerandom'
8
8
  require 'json'
9
- require 'bech32'
10
9
  require 'ffi'
11
10
  require 'observer'
12
11
  require 'tmpdir'
13
12
  require_relative 'openassets'
13
+ require_relative 'schnorr'
14
14
 
15
15
  module Tapyrus
16
16
 
17
+ autoload :Ext, 'tapyrus/ext'
17
18
  autoload :Util, 'tapyrus/util'
18
19
  autoload :ChainParams, 'tapyrus/chain_params'
19
20
  autoload :Message, 'tapyrus/message'
@@ -29,7 +30,6 @@ module Tapyrus
29
30
  autoload :TxIn, 'tapyrus/tx_in'
30
31
  autoload :TxOut, 'tapyrus/tx_out'
31
32
  autoload :OutPoint, 'tapyrus/out_point'
32
- autoload :ScriptWitness, 'tapyrus/script_witness'
33
33
  autoload :MerkleTree, 'tapyrus/merkle_tree'
34
34
  autoload :Key, 'tapyrus/key'
35
35
  autoload :ExtKey, 'tapyrus/ext_key'
@@ -46,18 +46,20 @@ module Tapyrus
46
46
  autoload :Wallet, 'tapyrus/wallet'
47
47
  autoload :BloomFilter, 'tapyrus/bloom_filter'
48
48
  autoload :KeyPath, 'tapyrus/key_path'
49
- autoload :Descriptor, 'tapyrus/descriptor'
50
49
  autoload :SLIP39, 'tapyrus/slip39'
50
+ autoload :Color, 'tapyrus/script/color'
51
+ autoload :Errors, 'tapyrus/errors'
51
52
 
52
53
  require_relative 'tapyrus/constants'
54
+ require_relative 'tapyrus/ext/ecdsa'
53
55
 
54
56
  extend Util
55
57
 
56
- @chain_param = :mainnet
58
+ @chain_param = :prod
57
59
 
58
60
  # set tapyrus network chain params
59
61
  def self.chain_params=(name)
60
- raise "chain params for #{name} is not defined." unless %i(mainnet testnet regtest).include?(name.to_sym)
62
+ raise "chain params for #{name} is not defined." unless %i(prod dev).include?(name.to_sym)
61
63
  @current_chain = nil
62
64
  @chain_param = name.to_sym
63
65
  end
@@ -66,12 +68,10 @@ module Tapyrus
66
68
  def self.chain_params
67
69
  return @current_chain if @current_chain
68
70
  case @chain_param
69
- when :mainnet
70
- @current_chain = Tapyrus::ChainParams.mainnet
71
- when :testnet
72
- @current_chain = Tapyrus::ChainParams.testnet
73
- when :regtest
74
- @current_chain = Tapyrus::ChainParams.regtest
71
+ when :prod
72
+ @current_chain = Tapyrus::ChainParams.prod
73
+ when :dev
74
+ @current_chain = Tapyrus::ChainParams.dev
75
75
  end
76
76
  @current_chain
77
77
  end
@@ -209,11 +209,4 @@ module Tapyrus
209
209
  end
210
210
  end
211
211
 
212
- class ::ECDSA::Signature
213
- # convert signature to der string.
214
- def to_der
215
- ECDSA::Format::SignatureDerString.encode(self)
216
- end
217
- end
218
-
219
212
  end
@@ -1,5 +1,6 @@
1
1
  module Tapyrus
2
2
  class Block
3
+ include Tapyrus::Util
3
4
 
4
5
  attr_accessor :header
5
6
  attr_accessor :transactions
@@ -21,23 +22,6 @@ module Tapyrus
21
22
  header.block_hash
22
23
  end
23
24
 
24
- # calculate block weight
25
- def weight
26
- stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
27
- end
28
-
29
- # calculate total size (include witness data.)
30
- def size
31
- 80 + Tapyrus.pack_var_int(transactions.size).bytesize +
32
- transactions.inject(0){|sum, tx| sum + (tx.witness? ? tx.serialize_witness_format.bytesize : tx.serialize_old_format.bytesize)}
33
- end
34
-
35
- # calculate base size (not include witness data.)
36
- def stripped_size
37
- 80 + Tapyrus.pack_var_int(transactions.size).bytesize +
38
- transactions.inject(0){|sum, tx| sum + tx.serialize_old_format.bytesize}
39
- end
40
-
41
25
  # check the merkle root in the block header matches merkle root calculated from tx list.
42
26
  def valid_merkle_root?
43
27
  calculate_merkle_root == header.merkle_root
@@ -48,29 +32,10 @@ module Tapyrus
48
32
  Tapyrus::MerkleTree.build_from_leaf(transactions.map(&:tx_hash)).merkle_root
49
33
  end
50
34
 
51
- # check the witness commitment in coinbase tx matches witness commitment calculated from tx list.
52
- def valid_witness_commitment?
53
- transactions[0].witness_commitment == calculate_witness_commitment
54
- end
55
-
56
- # calculate witness commitment from tx list.
57
- def calculate_witness_commitment
58
- witness_hashes = [COINBASE_WTXID]
59
- witness_hashes += (transactions[1..-1].map(&:witness_hash))
60
- reserved_value = transactions[0].inputs[0].script_witness.stack.map(&:bth).join
61
- root_hash = Tapyrus::MerkleTree.build_from_leaf(witness_hashes).merkle_root
62
- Tapyrus.double_sha256([root_hash + reserved_value].pack('H*')).bth
63
- end
64
-
65
35
  # return this block height. block height is included in coinbase.
66
- # if block version under 1, height does not include in coinbase, so return nil.
36
+ # @return [Integer] block height.
67
37
  def height
68
- return nil if header.version < 2
69
- coinbase_tx = transactions[0]
70
- return nil unless coinbase_tx.coinbase_tx?
71
- buf = StringIO.new(coinbase_tx.inputs[0].script_sig.to_payload)
72
- len = Tapyrus.unpack_var_int_from_io(buf)
73
- buf.read(len).reverse.bth.to_i(16)
38
+ transactions.first.in.first.out_point.index
74
39
  end
75
40
 
76
41
  end
@@ -2,61 +2,70 @@ module Tapyrus
2
2
 
3
3
  # Block Header
4
4
  class BlockHeader
5
+ include Tapyrus::HexConverter
6
+ extend Tapyrus::Util
7
+ include Tapyrus::Util
5
8
 
6
- attr_accessor :version
9
+ X_FILED_TYPES = {none: 0, aggregate_pubkey: 1}
10
+
11
+ attr_accessor :features
7
12
  attr_accessor :prev_hash
8
13
  attr_accessor :merkle_root
9
- attr_accessor :time # unix timestamp
10
- attr_accessor :bits
11
- attr_accessor :nonce
12
-
13
- def initialize(version, prev_hash, merkle_root, time, bits, nonce)
14
- @version = version
14
+ attr_accessor :im_merkle_root # merkel root of immulable merkle tree which consist of immutable txid.
15
+ attr_accessor :time # unix timestamp
16
+ attr_accessor :x_field_type
17
+ attr_accessor :x_field
18
+ attr_accessor :proof
19
+
20
+ def initialize(features, prev_hash, merkle_root, im_merkle_root, time, x_field_type, x_field, proof = nil)
21
+ @features = features
15
22
  @prev_hash = prev_hash
16
23
  @merkle_root = merkle_root
24
+ @im_merkle_root = im_merkle_root
17
25
  @time = time
18
- @bits = bits
19
- @nonce = nonce
26
+ @x_field_type = x_field_type
27
+ @x_field = x_field
28
+ @proof = proof
20
29
  end
21
30
 
22
31
  def self.parse_from_payload(payload)
23
- version, prev_hash, merkle_root, time, bits, nonce = payload.unpack('Va32a32VVV')
24
- new(version, prev_hash.bth, merkle_root.bth, time, bits, nonce)
25
- end
26
-
27
- def to_payload
28
- [version, prev_hash.htb, merkle_root.htb, time, bits, nonce].pack('Va32a32VVV')
32
+ buf = payload.is_a?(String) ? StringIO.new(payload) : payload
33
+ features, prev_hash, merkle_root, im_merkle_root, time, x_filed_type = buf.read(105).unpack('Va32a32a32Vc')
34
+ x_field = buf.read(unpack_var_int_from_io(buf)) unless x_filed_type == X_FILED_TYPES[:none]
35
+ proof = buf.read(unpack_var_int_from_io(buf))
36
+ new(features, prev_hash.bth, merkle_root.bth, im_merkle_root.bth, time, x_filed_type, x_field ? x_field.bth : x_field, proof.bth)
29
37
  end
30
38
 
31
- # compute difficulty target from bits.
32
- def difficulty_target
33
- exponent = ((bits >> 24) & 0xff)
34
- mantissa = bits & 0x7fffff
35
- mantissa *= -1 if (bits & 0x800000) > 0
36
- (mantissa * 2 ** (8 * (exponent - 3)))
39
+ def to_payload(skip_proof = false)
40
+ payload = [features, prev_hash.htb, merkle_root.htb, im_merkle_root.htb, time, x_field_type].pack('Va32a32a32Vc')
41
+ payload << pack_var_string(x_field.htb) unless x_field_type == X_FILED_TYPES[:none]
42
+ payload << pack_var_string(proof.htb) if proof && !skip_proof
43
+ payload
37
44
  end
38
45
 
39
- def hash
40
- calc_hash.to_i(16)
46
+ # Calculate hash using sign which does not contains proof.
47
+ # @return [String] hash of block without proof.
48
+ def hash_for_sign
49
+ Tapyrus.double_sha256(to_payload(true)).bth
41
50
  end
42
51
 
52
+ # Calculate block hash
53
+ # @return [String] hash of block with hex format.
43
54
  def block_hash
44
- calc_hash
55
+ Tapyrus.double_sha256(to_payload).bth
45
56
  end
46
57
 
47
58
  # block hash(big endian)
59
+ # @return [String] block id which is reversed version of block hash.
48
60
  def block_id
49
61
  block_hash.rhex
50
62
  end
51
63
 
52
64
  # evaluate block header
53
- def valid?
54
- valid_pow? && valid_timestamp?
55
- end
56
-
57
- # evaluate valid proof of work.
58
- def valid_pow?
59
- block_id.hex < difficulty_target
65
+ # @param [String] agg_pubkey aggregated public key for signers with hex format.
66
+ # @return [Boolean] result.
67
+ def valid?(agg_pubkey)
68
+ valid_timestamp? && valid_proof?(agg_pubkey) && valid_x_field?
60
69
  end
61
70
 
62
71
  # evaluate valid timestamp.
@@ -65,22 +74,42 @@ module Tapyrus
65
74
  time <= Time.now.to_i + Tapyrus::MAX_FUTURE_BLOCK_TIME
66
75
  end
67
76
 
68
- # compute chain work of this block.
69
- # @return [Integer] a chain work.
70
- def work
71
- target = difficulty_target
72
- return 0 if target < 1
73
- 115792089237316195423570985008687907853269984665640564039457584007913129639936.div(target + 1) # 115792089237316195423570985008687907853269984665640564039457584007913129639936 is 2**256
77
+ # Check whether proof is valid.
78
+ # @param [String] agg_pubkey aggregated public key for signers with hex format.
79
+ # @return [Boolean] Return true if proof is valid, otherwise return false.
80
+ def valid_proof?(agg_pubkey)
81
+ pubkey = Tapyrus::Key.new(pubkey: agg_pubkey)
82
+ msg = hash_for_sign.htb
83
+ pubkey.verify(proof.htb, msg, algo: :schnorr)
84
+ end
85
+
86
+ # Check whether x_field is valid.
87
+ # @return [Boolean] if valid return true, otherwise false
88
+ def valid_x_field?
89
+ case x_field_type
90
+ when X_FILED_TYPES[:none] then
91
+ x_field.nil?
92
+ when X_FILED_TYPES[:aggregate_pubkey] then
93
+ Tapyrus::Key.new(pubkey: x_field).fully_valid_pubkey?
94
+ else
95
+ false
96
+ end
97
+ end
98
+
99
+ # Check this header contains upgrade aggregated publiec key.
100
+ # @return [Boolean] if contains return true, otherwise false.
101
+ def upgrade_agg_pubkey?
102
+ x_field_type == X_FILED_TYPES[:aggregate_pubkey]
74
103
  end
75
104
 
76
105
  def ==(other)
77
106
  other && other.to_payload == to_payload
78
107
  end
79
108
 
80
- private
81
-
82
- def calc_hash
83
- Tapyrus.double_sha256(to_payload).bth
109
+ # get bytesize.
110
+ # @return [Integer] bytesize.
111
+ def size
112
+ to_payload.bytesize
84
113
  end
85
114
 
86
115
  end