Skip to content

Commit

Permalink
Merge pull request #301 from nervosnetwork/rc/v0.101.0
Browse files Browse the repository at this point in the history
  • Loading branch information
shaojunda authored Oct 25, 2021
2 parents d00d42e + 503b62c commit 1037b4b
Show file tree
Hide file tree
Showing 29 changed files with 463 additions and 138 deletions.
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
# [v0.101.0](https://github.com/shaojunda/ckb-sdk-ruby/compare/v0.41.0...v0.101.0) (2021-10-25)


### Bug Fixes

* default indexer collector ([1343c5e](https://github.com/shaojunda/ckb-sdk-ruby/commit/1343c5e))
* indexer collector bug ([64be7dd](https://github.com/shaojunda/ckb-sdk-ruby/commit/64be7dd))
* indexer collector bug ([15528e4](https://github.com/shaojunda/ckb-sdk-ruby/commit/15528e4))
* sudt amount ([2e64531](https://github.com/shaojunda/ckb-sdk-ruby/commit/2e64531))
* sudt cell dep duplicate ([1b86b04](https://github.com/shaojunda/ckb-sdk-ruby/commit/1b86b04))
* typo ([b1379b0](https://github.com/shaojunda/ckb-sdk-ruby/commit/b1379b0))


### Code Refactoring

* **hardfork:** rename uncles_hash to extra_hash ([ccd7545](https://github.com/shaojunda/ckb-sdk-ruby/commit/ccd7545))
* remove estimate_fee_rate RPC ([702f4c5](https://github.com/shaojunda/ckb-sdk-ruby/commit/702f4c5))


### Features

* **hardfork:** add a new field "hardfork_features" to get_consensus RPC ([ab2d4ca](https://github.com/shaojunda/ckb-sdk-ruby/commit/ab2d4ca))
* **hardfork:** add extension to block ([4f1461a](https://github.com/shaojunda/ckb-sdk-ruby/commit/4f1461a))
* **hardfork:** add new allowed value 'data1' to hash_type ([fec87fd](https://github.com/shaojunda/ckb-sdk-ruby/commit/fec87fd))
* **hardfork:** support new full payload address format ([80a9f97](https://github.com/shaojunda/ckb-sdk-ruby/commit/80a9f97))


### BREAKING CHANGES

* **hardfork:** The field "uncles_hash" in "header" will be renamed to "extra_hash"
https://github.com/nervosnetwork/ckb/pull/2776
* remove estimate_fee_rate API and RPC method


# [v0.41.0](https://github.com/nervosnetwork/ckb-sdk-ruby/compare/v0.40.0...v0.41.0) (2021-05-06)


Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
ckb-sdk-ruby (0.41.0)
ckb-sdk-ruby (0.101.0)
bitcoin-secp256k1 (~> 0.5.2)
net-http-persistent (~> 4.0.1)
rbnacl (~> 7.1.1)
Expand All @@ -15,7 +15,7 @@ GEM
coderay (1.1.2)
connection_pool (2.2.5)
diff-lcs (1.3)
ffi (1.15.0)
ffi (1.15.4)
jaro_winkler (1.5.2)
method_source (0.9.2)
net-http-persistent (4.0.1)
Expand Down
32 changes: 28 additions & 4 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
# [v0.41.0](https://github.com/nervosnetwork/ckb-sdk-ruby/compare/v0.40.0...v0.41.0) (2021-05-06)
# [v0.101.0](https://github.com/shaojunda/ckb-sdk-ruby/compare/v0.41.0...v0.101.0) (2021-10-25)


### Bug Fixes

* default indexer collector ([1343c5e](https://github.com/shaojunda/ckb-sdk-ruby/commit/1343c5e))
* indexer collector bug ([64be7dd](https://github.com/shaojunda/ckb-sdk-ruby/commit/64be7dd))
* indexer collector bug ([15528e4](https://github.com/shaojunda/ckb-sdk-ruby/commit/15528e4))
* sudt amount ([2e64531](https://github.com/shaojunda/ckb-sdk-ruby/commit/2e64531))
* sudt cell dep duplicate ([1b86b04](https://github.com/shaojunda/ckb-sdk-ruby/commit/1b86b04))
* typo ([b1379b0](https://github.com/shaojunda/ckb-sdk-ruby/commit/b1379b0))


### Code Refactoring

* **hardfork:** rename uncles_hash to extra_hash ([ccd7545](https://github.com/shaojunda/ckb-sdk-ruby/commit/ccd7545))
* remove estimate_fee_rate RPC ([702f4c5](https://github.com/shaojunda/ckb-sdk-ruby/commit/702f4c5))


### Features

* add generate_block_with_template RPC ([311a8d1](https://github.com/nervosnetwork/ckb-sdk-ruby/commit/311a8d1))
* implement get_cells_capacity api ([a4ade40](https://github.com/nervosnetwork/ckb-sdk-ruby/commit/a4ade40))
* support search key filter ([50d7ebb](https://github.com/nervosnetwork/ckb-sdk-ruby/commit/50d7ebb))
* **hardfork:** add a new field "hardfork_features" to get_consensus RPC ([ab2d4ca](https://github.com/shaojunda/ckb-sdk-ruby/commit/ab2d4ca))
* **hardfork:** add extension to block ([4f1461a](https://github.com/shaojunda/ckb-sdk-ruby/commit/4f1461a))
* **hardfork:** add new allowed value 'data1' to hash_type ([fec87fd](https://github.com/shaojunda/ckb-sdk-ruby/commit/fec87fd))
* **hardfork:** support new full payload address format ([80a9f97](https://github.com/shaojunda/ckb-sdk-ruby/commit/80a9f97))


### BREAKING CHANGES

* **hardfork:** The field "uncles_hash" in "header" will be renamed to "extra_hash"
https://github.com/nervosnetwork/ckb/pull/2776
* remove estimate_fee_rate API and RPC method
34 changes: 23 additions & 11 deletions lib/bech32.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Taken from https://github.com/sipa/bech32/blob/bdc264f84014c234e908d72026b7b780122be11f/ref/ruby/bech32.rb
# Taken from https://github.com/sipa/bech32/blob/master/ref/ruby/bech32.rb

# Copyright (c) 2017 Shigeyuki Azuchi
#
Expand All @@ -22,25 +22,30 @@

module Bech32

module Encoding
BECH32 = 1
BECH32M = 2
end

SEPARATOR = '1'

CHARSET = %w(q p z r y 9 x 8 g f 2 t v d w 0 s 3 j n 5 4 k h c e 6 m u a 7 l)

BECH32M_CONST = 0x2bc830a3

module_function

# Encode Bech32 string
def encode(hrp, data)
checksummed = data + create_checksum(hrp, data)
def encode(hrp, data, spec)
checksummed = data + create_checksum(hrp, data, spec)
hrp + SEPARATOR + checksummed.map{|i|CHARSET[i]}.join
end

# Decode a Bech32 string and determine hrp and data
def decode(bech)
# check invalid bytes
return nil if bech.scrub('?').include?('?')
# check uppercase/lowercase
return nil if bech.bytes.index{|x| x < 33 || x > 126}
return nil if (bech.downcase != bech && bech.upcase != bech)
bech.each_char{|c|return nil if c.ord < 33 || c.ord > 126}
bech = bech.downcase
# check data length
pos = bech.rindex(SEPARATOR)
Expand All @@ -51,20 +56,27 @@ def decode(bech)
hrp = bech[0..pos-1]
data = bech[pos+1..-1].each_char.map{|c|CHARSET.index(c)}
# check checksum
return nil unless verify_checksum(hrp, data)
[hrp, data[0..-7]]
spec = verify_checksum(hrp, data)
spec ? [hrp, data[0..-7], spec] : nil
end

# Compute the checksum values given hrp and data.
def create_checksum(hrp, data)
def create_checksum(hrp, data, spec)
values = expand_hrp(hrp) + data
polymod = polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1
const = (spec == Bech32::Encoding::BECH32M ? Bech32::BECH32M_CONST : 1)
polymod = polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
(0..5).map{|i|(polymod >> 5 * (5 - i)) & 31}
end

# Verify a checksum given Bech32 string
def verify_checksum(hrp, data)
polymod(expand_hrp(hrp) + data) == 1
const = polymod(expand_hrp(hrp) + data)
case const
when 1
Encoding::BECH32
when BECH32M_CONST
Encoding::BECH32M
end
end

# Expand the hrp into values for checksum computation.
Expand Down
40 changes: 32 additions & 8 deletions lib/ckb/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

module CKB
class Address
attr_reader :script, :prefix, :mode
attr_reader :script, :prefix, :mode, :version

PREFIX_MAINNET = "ckb"
PREFIX_TESTNET = "ckt"
DEFAULT_MODE = MODE::TESTNET
FULL_WITH_IDENTIFIER_FORMAT = "00"
SHORT_FORMAT = "01"
FULL_DATA_FORMAT = "02"
FULL_TYPE_FORMAT = "04"
Expand All @@ -15,12 +16,18 @@ class Address
CODE_HASH_INDEX_ANYONE_CAN_PAY = "02"
SHORT_PAYLOAD_AVAILABLE_ARGS_LEN = [20, 21, 22].freeze

module Version
CKB2019 = 1
CKB2021 = 2
end

# @param script [CKB::Types::Script]
# @param mode [String]
def initialize(script, mode: DEFAULT_MODE)
def initialize(script, mode: DEFAULT_MODE, version: CKB::Address::Version::CKB2021)
@script = script
@mode = mode
@prefix = self.class.prefix(mode: mode)
@version = version
end

# Generates address assuming default lock script is used
Expand Down Expand Up @@ -71,7 +78,7 @@ def short_payload(code_hash_index)
#
# @return [String]
def generate_short_payload_singlesig_address
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_SINGLESIG))
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_SINGLESIG), Bech32::Encoding::BECH32)
end

# Generates short payload format address
Expand All @@ -80,7 +87,7 @@ def generate_short_payload_singlesig_address
#
# @return [String]
def generate_short_payload_multisig_address
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_MULTISIG_SIG))
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_MULTISIG_SIG), Bech32::Encoding::BECH32)
end

# Generates short payload format address
Expand All @@ -89,7 +96,7 @@ def generate_short_payload_multisig_address
#
# @return [String]
def generate_short_payload_anyone_can_pay_address
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_ANYONE_CAN_PAY))
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_ANYONE_CAN_PAY), Bech32::Encoding::BECH32)
end

# Generates full payload format address
Expand All @@ -98,13 +105,30 @@ def generate_short_payload_anyone_can_pay_address
#
# @return [String]
def generate_full_payload_address
format_type = CKB::ScriptHashType::TYPE == script.hash_type ? FULL_TYPE_FORMAT : FULL_DATA_FORMAT
case version
when CKB::Address::Version::CKB2019
format_type = CKB::ScriptHashType::TYPE == script.hash_type ? FULL_TYPE_FORMAT : FULL_DATA_FORMAT
CKB::ConvertAddress.encode(prefix, first_version_full_payload(format_type), Bech32::Encoding::BECH32)
when CKB::Address::Version::CKB2021
# payload = 0x00 | code_hash | hash_type | args
CKB::ConvertAddress.encode(prefix, current_version_full_payload(FULL_WITH_IDENTIFIER_FORMAT), Bech32::Encoding::BECH32M)
else
raise InvalidVersionError, "invalid address version"
end
end

def first_version_full_payload(format_type)
args = script.has_args? ? CKB::Utils.hex_to_bin(script.args) : ""
payload = [format_type].pack("H*") + CKB::Utils.hex_to_bin(script.code_hash) + args
[format_type].pack("H*") + CKB::Utils.hex_to_bin(script.code_hash) + args
end

CKB::ConvertAddress.encode(prefix, payload)
def current_version_full_payload(format_type)
args = script.has_args? ? CKB::Utils.hex_to_bin(script.args) : ""
hash_type = [CKB::ScriptHashType::TYPES.index(script.hash_type)].pack("C")
[format_type].pack("H*") + CKB::Utils.hex_to_bin(script.code_hash) + hash_type + args
end

class InvalidModeError < StandardError; end
class InvalidVersionError < StandardError; end
end
end
40 changes: 30 additions & 10 deletions lib/ckb/address_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ def initialize(address)
end

def parse
decoded_prefix, data = ConvertAddress.decode(address)
decoded_prefix, data, spec = ConvertAddress.decode(address)
format_type = data[0].unpack("H*").first

case format_type
when Address::SHORT_FORMAT
parse_short_payload_address(decoded_prefix, data)
parse_short_payload_address(decoded_prefix, data, spec)
when Address::FULL_DATA_FORMAT, Address::FULL_TYPE_FORMAT
parse_full_payload_address(decoded_prefix, data)
parse_full_payload_address(decoded_prefix, data, spec)
when Address::FULL_WITH_IDENTIFIER_FORMAT
parse_new_full_payload_address(decoded_prefix, data, spec)
else
raise InvalidFormatTypeError, "Invalid format type"
end
Expand All @@ -40,7 +41,7 @@ def parse_address_type(format_type, code_hash_index = nil)
end
end

def parse_short_payload_address(decoded_prefix, data)
def parse_short_payload_address(decoded_prefix, data, spec)
format_type = data[0].unpack("H*").first
code_hash_index = data[1].unpack("H*").first
mode = parse_mode(decoded_prefix)
Expand All @@ -49,19 +50,26 @@ def parse_short_payload_address(decoded_prefix, data)
if code_hash_index != CKB::Address::CODE_HASH_INDEX_ANYONE_CAN_PAY && CKB::Utils.hex_to_bin(args).bytesize != 20
raise InvalidArgSizeError, "Short payload format address args bytesize must equal to 20"
end
if spec != Bech32::Encoding::BECH32
raise InvalidEncodingError, "short address must use bech32 encoding"
end

OpenStruct.new(mode: mode,
script: CKB::Types::Script.new(code_hash: code_hash, args: args, hash_type: CKB::ScriptHashType::TYPE), address_type: parse_address_type(format_type, code_hash_index))
end

def parse_full_payload_address(decoded_prefix, data)
def parse_full_payload_address(decoded_prefix, data, spec)
format_type = data[0].unpack("H*").first
mode = parse_mode(decoded_prefix)
hash_type = parse_hash_type(format_type)
offset = 1
code_hash_size = 32
raise InvalidCodeHashSizeError, "CodeHash bytesize must equal to 32" if data[1..-1].size < code_hash_size

if spec != Bech32::Encoding::BECH32
raise InvalidEncodingError, "ckb2019 format full address must use bech32 encoding"
end

code_hash = "0x#{data.slice(1..code_hash_size).unpack('H*').first}"
offset += code_hash_size
args = CKB::Utils.bin_to_hex(data[offset..-1])
Expand All @@ -70,6 +78,21 @@ def parse_full_payload_address(decoded_prefix, data)
script: CKB::Types::Script.new(code_hash: code_hash, args: args, hash_type: hash_type), address_type: parse_address_type(format_type))
end

def parse_new_full_payload_address(decoded_prefix, data, spec)
format_type = data[0].unpack("H*").first
mode = parse_mode(decoded_prefix)
code_hash_size = 32
raise InvalidCodeHashSizeError, "CodeHash bytesize must equal to 32" if data[1..-1].size < code_hash_size
if spec != Bech32::Encoding::BECH32M
raise InvalidEncodingError, "ckb2021 format full address must use bech32m encoding"
end
code_hash = "0x#{data.slice(1..code_hash_size).unpack('H*').first}"
hash_type = CKB::Utils.bin_to_hex(data[code_hash_size + 1...code_hash_size + 2]).hex
args = CKB::Utils.bin_to_hex(data[code_hash_size + 2..-1])
OpenStruct.new(mode: mode,
script: CKB::Types::Script.new(code_hash: code_hash, args: args, hash_type: CKB::ScriptHashType::TYPES[hash_type]), address_type: parse_address_type(format_type))
end

def parse_hash_type(format_type)
case format_type
when Address::FULL_DATA_FORMAT
Expand Down Expand Up @@ -110,13 +133,10 @@ def parse_mode(decoded_prefix)
end

class InvalidFormatTypeError < StandardError; end

class InvalidArgSizeError < StandardError; end

class InvalidPrefixError < StandardError; end

class InvalidCodeHashIndexError < StandardError; end

class InvalidCodeHashSizeError < StandardError; end
class InvalidEncodingError < StandardError; end
end
end
8 changes: 4 additions & 4 deletions lib/ckb/convert_address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ def convert_bits(data, from, to, padding = true)
ret
end

def encode(hrp, data)
def encode(hrp, data, spec)
data = convert_bits(data.bytes, 8, 5)
Bech32.encode(hrp, data)
Bech32.encode(hrp, data, spec)
end

def decode(bech)
hrp, data = Bech32.decode(bech)
[hrp, convert_bits(data, 5, 8, false).map(&:chr).join]
hrp, data, spec = Bech32.decode(bech)
[hrp, convert_bits(data, 5, 8, false).map(&:chr).join, spec]
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/ckb/script_hash_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module CKB
module ScriptHashType
TYPES = [TYPE = "type", DATA = "data"].freeze
TYPES = [DATA = "data", TYPE = "type", DATA1 = "data1"].freeze
end
end
Loading

0 comments on commit 1037b4b

Please sign in to comment.