Skip to content

Commit

Permalink
feat: parse btc time lock cell (#1808)
Browse files Browse the repository at this point in the history
  • Loading branch information
rabbitz authored Apr 20, 2024
1 parent 62e3edd commit e4a7ddd
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
12 changes: 9 additions & 3 deletions app/models/concerns/ckb_transactions/bitcoin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ def rgb_commitment
end

def rgb_txid
return unless rgb_transaction?

bitcoin_transaction&.txid
if rgb_transaction?
bitcoin_transaction&.txid

Check warning on line 30 in app/models/concerns/ckb_transactions/bitcoin.rb

View check run for this annotation

Codecov / codecov/patch

app/models/concerns/ckb_transactions/bitcoin.rb#L30

Added line #L30 was not covered by tests
elsif btc_time_transaction?
btc_time_lock_cell =
inputs.includes(:lock_script).find_by(lock_scripts: { code_hash: CkbSync::Api.instance.btc_time_code_hash }) ||

Check warning on line 33 in app/models/concerns/ckb_transactions/bitcoin.rb

View check run for this annotation

Codecov / codecov/patch

app/models/concerns/ckb_transactions/bitcoin.rb#L33

Added line #L33 was not covered by tests
outputs.includes(:lock_script).find_by(lock_scripts: { code_hash: CkbSync::Api.instance.btc_time_code_hash })
parsed_args = CkbUtils.parse_btc_time_lock_cell(btc_time_lock_cell.lock_script.args)
parsed_args.txid

Check warning on line 36 in app/models/concerns/ckb_transactions/bitcoin.rb

View check run for this annotation

Codecov / codecov/patch

app/models/concerns/ckb_transactions/bitcoin.rb#L35-L36

Added lines #L35 - L36 were not covered by tests
end
end

def leap_direction
Expand Down
28 changes: 28 additions & 0 deletions app/utils/ckb_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,34 @@ def self.is_btc_time_lock_cell?(lock_script)
lock_script.code_hash == CkbSync::Api.instance.btc_time_code_hash && lock_script.hash_type == "type"
end

def self.parse_btc_time_lock_cell(args)
args_serialization = [args.delete_prefix("0x")].pack("H*")
script_offset = [args_serialization[4..7].unpack1("H*")].pack("H*").unpack1("V")
after_offset = [args_serialization[8..11].unpack1("H*")].pack("H*").unpack1("V")
txid_offset = [args_serialization[12..15].unpack1("H*")].pack("H*").unpack1("V")

script_serialization = args_serialization[script_offset...after_offset]
code_hash_offset = [script_serialization[4..7].unpack1("H*")].pack("H*").unpack1("V")
hash_type_offset = [script_serialization[8..11].unpack1("H*")].pack("H*").unpack1("V")
args_offset = [script_serialization[12..15].unpack1("H*")].pack("H*").unpack1("V")
script_code_hash_serialization = script_serialization[code_hash_offset...hash_type_offset]
script_hash_type_serialization = script_serialization[hash_type_offset...args_offset]
script_args_serialization = script_serialization[hash_type_offset + 1..]
code_hash = "0x#{script_code_hash_serialization.unpack1('H*')}"
hash_type_hex = "0x#{script_hash_type_serialization.unpack1('H*')}"
hash_type = hash_type_hex == "0x00" ? "data" : "type"
args = "0x#{script_args_serialization.unpack1('H*')}"
lock = CKB::Types::Script.new(code_hash:, args:, hash_type:)

after_serialization = args_serialization[after_offset...txid_offset]
after = [after_serialization.unpack1("H*")].pack("H*").unpack1("V")

txid_serialization = args_serialization[txid_offset..]
txid = txid_serialization.unpack1("H*").scan(/../).reverse.join

OpenStruct.new(lock:, after:, txid:)
end

# * https://learnmeabitcoin.com/technical/general/byte-order/
# Whenever you're working with transaction/block hashes internally (e.g. inside raw bitcoin data), you use the natural byte order.
# Whenever you're displaying or searching for transaction/block hashes, you use the reverse byte order.
Expand Down
11 changes: 11 additions & 0 deletions test/utils/ckb_utils_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,17 @@ class CkbUtilsTest < ActiveSupport::TestCase
assert_equal commitment, "7cdecc8cc293d491a0cbf44e92feabfc29e79408c1d2f7547b334c42efe13131"
end

test "parse btc time lock args" do
args = "0x7d00000010000000590000005d000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce801140000000ba4ece3bd6d00fc9f3d828a909c3c6384c9c5130600000001e1a7d37d4580db85942b3a3771189635fba2bffd6e65aaa31c3411a8248236"
parsed_args = CkbUtils.parse_btc_time_lock_cell(args)

assert_equal "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", parsed_args.lock.code_hash
assert_equal "type", parsed_args.lock.hash_type
assert_equal "0x140000000ba4ece3bd6d00fc9f3d828a909c3c6384c9c513", parsed_args.lock.args
assert_equal 6, parsed_args.after
assert_equal "368224a811341ca3aa656efdbfa2fb35961871373a2b9485db80457dd3a7e101", parsed_args.txid
end

private

def node_data_processor
Expand Down

0 comments on commit e4a7ddd

Please sign in to comment.