Skip to content

Commit

Permalink
Merge pull request #273 from nervosnetwork/shaojunda-support-acp-shor…
Browse files Browse the repository at this point in the history
…t-address
  • Loading branch information
shaojunda authored Nov 25, 2020
2 parents 53f32c6 + d7ff897 commit b587cd5
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
ckb-sdk-ruby (0.37.0)
ckb-sdk-ruby (0.38.0)
bitcoin-secp256k1 (~> 0.5.2)
net-http-persistent (~> 3.1.0)
rbnacl (~> 7.1.1)
Expand Down
16 changes: 14 additions & 2 deletions lib/ckb/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Address
FULL_TYPE_FORMAT = "04"
CODE_HASH_INDEX_SINGLESIG = "00"
CODE_HASH_INDEX_MULTISIG_SIG = "01"
CODE_HASH_INDEX_ANYONE_CAN_PAY = "02"
SHORT_PAYLOAD_AVAILABLE_ARGS_LEN = [20, 21, 22]

# @param script [CKB::Types::Script]
# @param mode [String]
Expand All @@ -25,14 +27,15 @@ def initialize(script, mode: DEFAULT_MODE)
# payload = type(01) | code hash index(00) | pubkey blake160
# see https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0021-ckb-address-format/0021-ckb-address-format.md for more info.
def generate
unless CKB::ScriptHashType::TYPE == script.hash_type && script.has_args? && CKB::Utils.hex_to_bin(script.args).bytesize == 20
unless CKB::ScriptHashType::TYPE == script.hash_type && script.has_args? && (SHORT_PAYLOAD_AVAILABLE_ARGS_LEN.include?(CKB::Utils.hex_to_bin(script.args).bytesize))
return generate_full_payload_address
end

if SystemCodeHash::SECP256K1_BLAKE160_SIGHASH_ALL_TYPE_HASH == script.code_hash
generate_short_payload_singlesig_address
elsif SystemCodeHash::SECP256K1_BLAKE160_MULTISIG_ALL_TYPE_HASH == script.code_hash
generate_short_payload_multisig_address
elsif [SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON].include?(script.code_hash)
generate_short_payload_anyone_can_pay_address
else
generate_full_payload_address
end
Expand Down Expand Up @@ -78,6 +81,15 @@ def generate_short_payload_multisig_address
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_MULTISIG_SIG))
end

# Generates short payload format address
# payload = type(01) | code hash index(02) | args
# see https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0021-ckb-address-format/0021-ckb-address-format.md for more info.
#
# @return [String]
def generate_short_payload_anyone_can_pay_address
ConvertAddress.encode(prefix, short_payload(CODE_HASH_INDEX_ANYONE_CAN_PAY))
end

# Generates full payload format address
# payload = 0x02/0x04 | code_hash | args
# see https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0021-ckb-address-format/0021-ckb-address-format.md for more info.
Expand Down
14 changes: 11 additions & 3 deletions lib/ckb/address_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def parse_address_type(format_type, code_hash_index = nil)
"SHORTSINGLESIG"
when Address::CODE_HASH_INDEX_MULTISIG_SIG
"SHORTMULTISIG"
when Address::CODE_HASH_INDEX_ANYONE_CAN_PAY
"SHORTANYONECANPAY"
else
raise InvalidCodeHashIndexError, "Invalid code hash index"
end
Expand All @@ -42,9 +44,9 @@ def parse_short_payload_address(decoded_prefix, data)
format_type = data[0].unpack("H*").first
code_hash_index = data[1].unpack("H*").first
mode = parse_mode(decoded_prefix)
code_hash = parse_code_hash(code_hash_index)
code_hash = parse_code_hash(code_hash_index, mode)
args = CKB::Utils.bin_to_hex(data.slice(2..-1))
if CKB::Utils.hex_to_bin(args).bytesize != 20
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

Expand Down Expand Up @@ -77,12 +79,18 @@ def parse_hash_type(format_type)
end
end

def parse_code_hash(code_hash_index)
def parse_code_hash(code_hash_index, mode)
case code_hash_index
when Address::CODE_HASH_INDEX_SINGLESIG
SystemCodeHash::SECP256K1_BLAKE160_SIGHASH_ALL_TYPE_HASH
when Address::CODE_HASH_INDEX_MULTISIG_SIG
SystemCodeHash::SECP256K1_BLAKE160_MULTISIG_ALL_TYPE_HASH
when Address::CODE_HASH_INDEX_ANYONE_CAN_PAY
if mode == CKB::MODE::TESTNET
SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON
else
SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA
end
else
raise InvalidCodeHashIndexError, "Invalid code hash index"
end
Expand Down
2 changes: 2 additions & 0 deletions lib/ckb/system_code_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ module SystemCodeHash
SECP256K1_BLAKE160_SIGHASH_ALL_DATA_HASH = "0x973bdb373cbb1d752b4ac006e2bb5bdcb63431ed2b6e394b22721c8906a2ad72"
SECP256K1_BLAKE160_SIGHASH_ALL_TYPE_HASH = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"
SECP256K1_BLAKE160_MULTISIG_ALL_TYPE_HASH = "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8"
ANYONE_CAN_PAY_CODE_HASH_ON_LINA = "0xd369597ff47f29fbc0d47d2e3775370d1250b85140c670e4718af712983a2354"
ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON = "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356"
end
end
70 changes: 70 additions & 0 deletions spec/ckb/address_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,46 @@
expect(parsed_address.address_type).to eq "SHORTMULTISIG"
end

it "parse short payload acp address without minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a")
parsed_address = CKB::AddressParser.new("ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaq3xzhsz").parse
expect(parsed_address.mode).to eq CKB::MODE::TESTNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse short payload acp address with ckb minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c")
parsed_address = CKB::AddressParser.new("ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaqc9q8fqw").parse
expect(parsed_address.mode).to eq CKB::MODE::TESTNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse short payload acp address with ckb and udt minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c01")
parsed_address = CKB::AddressParser.new("ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaqcqgr072sz").parse
expect(parsed_address.mode).to eq CKB::MODE::TESTNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse full payload acp address with ckb and udt minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101")
parsed_address = CKB::AddressParser.new("ckt1qs6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vnajhch96rq68wrff7pjx59r8stgt4rh5rqpqy2a9ak4").parse
expect(parsed_address.mode).to eq CKB::MODE::TESTNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "FULL"
end

it "parse full payload data address" do
parsed_address = CKB::AddressParser.new(full_payload_data_address).parse
expect(parsed_address.mode).to eq CKB::MODE::TESTNET
Expand Down Expand Up @@ -118,6 +158,36 @@
expect(parsed_address.address_type).to eq "SHORTMULTISIG"
end

it "parse short payload acp address without minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a")
parsed_address = CKB::AddressParser.new("ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqvrugu7").parse
expect(parsed_address.mode).to eq CKB::MODE::MAINNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse short payload acp address with ckb minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c")
parsed_address = CKB::AddressParser.new("ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqcehzz9g").parse
expect(parsed_address.mode).to eq CKB::MODE::MAINNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse short payload acp address with ckb and udt minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c01")
parsed_address = CKB::AddressParser.new("ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqcqgzc5xlw").parse
expect(parsed_address.mode).to eq CKB::MODE::MAINNET
expect(parsed_address.script.args).to eq acp_lock.args
expect(parsed_address.script.code_hash).to eq acp_lock.code_hash
expect(parsed_address.script.hash_type).to eq acp_lock.hash_type
expect(parsed_address.address_type).to eq "SHORTANYONECANPAY"
end

it "parse full payload data address" do
parsed_address = CKB::AddressParser.new(full_payload_data_address).parse
expect(parsed_address.mode).to eq CKB::MODE::MAINNET
Expand Down
64 changes: 64 additions & 0 deletions spec/ckb/address_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,38 @@
).to eq "ckt1qyqlqn8vsj7r0a5rvya76tey9jd2rdnca8lqh4kcuq"
end

it "generate short payload anyone can pay address without minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a")
address = CKB::Address.new(acp_lock)
expect(
address.generate
).to eq "ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaq3xzhsz"
end

it "generate short payload anyone can pay address with ckb minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c")
address = CKB::Address.new(acp_lock)
expect(
address.generate
).to eq "ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaqc9q8fqw"
end

it "generate short payload anyone can pay address with ckb and udt minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c01")
address = CKB::Address.new(acp_lock)
expect(
address.generate
).to eq "ckt1qypylv479ewscx3ms620sv34pgeuz6zagaaqcqgr072sz"
end

it "generate full payload address when acp lock args is more than 22 bytes" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_AGGRON, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101")
address = CKB::Address.new(acp_lock)
expect(
address.generate
).to eq "ckt1qs6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vnajhch96rq68wrff7pjx59r8stgt4rh5rqpqy2a9ak4"
end

it "generate full payload data address" do
address = CKB::Address.new(full_data_script)
expect(
Expand Down Expand Up @@ -71,6 +103,38 @@
).to eq "ckb1qyqlqn8vsj7r0a5rvya76tey9jd2rdnca8lq2sg8su"
end

it "generate short payload anyone can pay address without minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a")
address = CKB::Address.new(acp_lock, mode: CKB::MODE::MAINNET)
expect(
address.generate
).to eq "ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqvrugu7"
end

it "generate short payload anyone can pay address with ckb minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c")
address = CKB::Address.new(acp_lock, mode: CKB::MODE::MAINNET)
expect(
address.generate
).to eq "ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqcehzz9g"
end

it "generate short payload anyone can pay address with ckb and udt minimum limit" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c01")
address = CKB::Address.new(acp_lock, mode: CKB::MODE::MAINNET)
expect(
address.generate
).to eq "ckb1qypylv479ewscx3ms620sv34pgeuz6zagaaqcqgzc5xlw"
end

it "generate full payload address when acp lock args is more than 22 bytes" do
acp_lock = CKB::Types::Script.new(code_hash: CKB::SystemCodeHash::ANYONE_CAN_PAY_CODE_HASH_ON_LINA, hash_type: "type", args: "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101")
address = CKB::Address.new(acp_lock, mode: CKB::MODE::MAINNET)
expect(
address.generate
).to eq "ckb1qnfkjktl73ljn77q637judm4xux3y59c29qvvu8ywx90wy5c8g34gnajhch96rq68wrff7pjx59r8stgt4rh5rqpqy532xj3"
end

it "generate full payload data address" do
address = CKB::Address.new(full_data_script, mode: CKB::MODE::MAINNET)
expect(
Expand Down

0 comments on commit b587cd5

Please sign in to comment.