Skip to content

Commit

Permalink
[Bitcoin] Implement bitcoin Inscription parse in Move (#1182)
Browse files Browse the repository at this point in the history
* [Bitcoin] Implement bitcoin Inscription parse in Move

* fixup
  • Loading branch information
jolestar authored Nov 29, 2023
1 parent e8bd1d8 commit 492071d
Show file tree
Hide file tree
Showing 26 changed files with 2,750 additions and 22 deletions.
12 changes: 7 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ bitcoin = { version = "0.31.0", features = ["rand-std"] }
bitcoincore-rpc = "0.18.0"
bip32 = "0.4.0"
byteorder = "1.4.3"
brotli = "3.4.0"
clap = { version = "3.2.23", features = ["derive", "env"] }
chrono = "0.4.23"
coerce = "0.8"
Expand Down Expand Up @@ -189,6 +190,7 @@ rocksdb = { version = "0.21.0", features = ["snappy", "lz4", "zstd", "zlib", "mu
prometheus = "0.13.3"
coarsetime = "0.1.22"
hyper = { version = "0.14.12", features = ["full"] }
http = "0.2.6"
num_enum = "0.5.7"
libc = "^0.2"
nostr = "0.22"
Expand Down
1 change: 1 addition & 0 deletions crates/rooch-framework-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ mod empty_tests;
mod ethereum_light_client_test;
mod ethereum_validator_tests;
mod native_validator_tests;
mod ord_test;
mod transaction_validator_tests;
30 changes: 30 additions & 0 deletions crates/rooch-framework-tests/src/tests/ord_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::binding_test;
use bitcoin::consensus::Decodable;
use hex::FromHex;
use rooch_types::framework::ord::Inscription;

#[test]
fn test_ord() {
tracing_subscriber::fmt::init();
let binding_test = binding_test::RustBindingTest::new().unwrap();

//https://mempool.space/api/tx/a03c44005f1871a6068e286a4151b009e3f6184983464782820b56633760333d/hex
let btc_tx_hex = "02000000000101361cc743a923abc1db73f4fed4d0778cc8ccc092cb20f1c66cada177818e55b20000000000fdffffff022202000000000000225120e5053d2151d14399a3a4825740e14deae6f984e990e0a6872df065a6dad7009c6e04000000000000160014ad45c620bd9b6688c5a7a23e515402d39d02b55203401500c4f407f66ec47c92e1daf34c46f2b52837819119b696e343385b6dba27682dd89f9e4d18354ce0f4a4200ddab8420457392702e1e0b6d51803d25d2bf2647f2016c3a3f18eb4efd24274941ba02c899d151b0473a1bad3512423cbe1b0648ea9ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800397b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a226f726469222c22616d74223a2231303030227d6821c102a58d972468a33a79350cf24cb991f28adbbe3e64e88ded5f58f558fff2b67300000000";
let btc_tx_bytes = Vec::from_hex(btc_tx_hex).unwrap();
let btc_tx: bitcoin::Transaction =
Decodable::consensus_decode(&mut btc_tx_bytes.as_slice()).unwrap();
let inscriptions =
rooch_framework::natives::rooch_framework::bitcoin::ord::from_transaction(&btc_tx).unwrap();
//print!("{:?}", inscriptions);
let ord_module = binding_test.as_module_bundle::<rooch_types::framework::ord::OrdModule>();

let inscriptions_from_move = ord_module.from_transaction(&btc_tx.into()).unwrap();
assert_eq!(inscriptions.len(), inscriptions_from_move.len());
for (inscription, inscription_from_move) in inscriptions.into_iter().zip(inscriptions_from_move)
{
assert_eq!(Inscription::from(inscription), inscription_from_move);
}
}
2 changes: 2 additions & 0 deletions crates/rooch-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rust-version = { workspace = true }
anyhow = { workspace = true }
bcs = { workspace = true }
better_any = { workspace = true }
brotli = { workspace = true }
fastcrypto = { workspace = true }
linked-hash-map = { workspace = true }
once_cell = { workspace = true }
Expand All @@ -29,6 +30,7 @@ rust_secp256k1 = { workspace = true }
bitcoin = { workspace = true }
bitcoin-bech32 = { workspace = true }
bs58 = { workspace = true, features = ["check"] }
http = { workspace = true }

move-binary-format = { workspace = true }
move-bytecode-utils = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions crates/rooch-framework/doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ This is the reference documentation of the Rooch Framework.
- [`0x3::hash`](hash.md#0x3_hash)
- [`0x3::multichain_address`](multichain_address.md#0x3_multichain_address)
- [`0x3::native_validator`](native_validator.md#0x3_native_validator)
- [`0x3::ord`](ord.md#0x3_ord)
- [`0x3::schnorr`](schnorr.md#0x3_schnorr)
- [`0x3::session_key`](session_key.md#0x3_session_key)
- [`0x3::timestamp`](timestamp.md#0x3_timestamp)
Expand Down
68 changes: 66 additions & 2 deletions crates/rooch-framework/doc/bitcoin_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [Struct `Header`](#0x3_bitcoin_types_Header)
- [Struct `Transaction`](#0x3_bitcoin_types_Transaction)
- [Struct `TxIn`](#0x3_bitcoin_types_TxIn)
- [Struct `Witness`](#0x3_bitcoin_types_Witness)
- [Struct `OutPoint`](#0x3_bitcoin_types_OutPoint)
- [Struct `TxOut`](#0x3_bitcoin_types_TxOut)
- [Constants](#@Constants_0)
Expand All @@ -29,6 +30,9 @@
- [Function `txin_script_sig`](#0x3_bitcoin_types_txin_script_sig)
- [Function `txin_sequence`](#0x3_bitcoin_types_txin_sequence)
- [Function `txin_witness`](#0x3_bitcoin_types_txin_witness)
- [Function `witness_nth`](#0x3_bitcoin_types_witness_nth)
- [Function `witness_len`](#0x3_bitcoin_types_witness_len)
- [Function `witness_tapscript`](#0x3_bitcoin_types_witness_tapscript)
- [Function `new_outpoint`](#0x3_bitcoin_types_new_outpoint)
- [Function `outpoint_txid`](#0x3_bitcoin_types_outpoint_txid)
- [Function `outpoint_vout`](#0x3_bitcoin_types_outpoint_vout)
Expand All @@ -38,7 +42,8 @@
- [Function `unpack_txout`](#0x3_bitcoin_types_unpack_txout)


<pre><code><b>use</b> <a href="bitcoin_script_buf.md#0x3_bitcoin_script_buf">0x3::bitcoin_script_buf</a>;
<pre><code><b>use</b> <a href="">0x1::option</a>;
<b>use</b> <a href="bitcoin_script_buf.md#0x3_bitcoin_script_buf">0x3::bitcoin_script_buf</a>;
</code></pre>


Expand Down Expand Up @@ -87,6 +92,17 @@



<a name="0x3_bitcoin_types_Witness"></a>

## Struct `Witness`



<pre><code><b>struct</b> <a href="bitcoin_types.md#0x3_bitcoin_types_Witness">Witness</a> <b>has</b> <b>copy</b>, drop, store
</code></pre>



<a name="0x3_bitcoin_types_OutPoint"></a>

## Struct `OutPoint`
Expand Down Expand Up @@ -123,6 +139,15 @@



<a name="0x3_bitcoin_types_TAPROOT_ANNEX_PREFIX"></a>



<pre><code><b>const</b> <a href="bitcoin_types.md#0x3_bitcoin_types_TAPROOT_ANNEX_PREFIX">TAPROOT_ANNEX_PREFIX</a>: u8 = 80;
</code></pre>



<a name="0x3_bitcoin_types_header"></a>

## Function `header`
Expand Down Expand Up @@ -305,7 +330,46 @@



<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_types.md#0x3_bitcoin_types_txin_witness">txin_witness</a>(self: &<a href="bitcoin_types.md#0x3_bitcoin_types_TxIn">bitcoin_types::TxIn</a>): &<a href="">vector</a>&lt;u8&gt;
<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_types.md#0x3_bitcoin_types_txin_witness">txin_witness</a>(self: &<a href="bitcoin_types.md#0x3_bitcoin_types_TxIn">bitcoin_types::TxIn</a>): &<a href="bitcoin_types.md#0x3_bitcoin_types_Witness">bitcoin_types::Witness</a>
</code></pre>



<a name="0x3_bitcoin_types_witness_nth"></a>

## Function `witness_nth`



<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_types.md#0x3_bitcoin_types_witness_nth">witness_nth</a>(self: &<a href="bitcoin_types.md#0x3_bitcoin_types_Witness">bitcoin_types::Witness</a>, nth: u64): &<a href="">vector</a>&lt;u8&gt;
</code></pre>



<a name="0x3_bitcoin_types_witness_len"></a>

## Function `witness_len`



<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_types.md#0x3_bitcoin_types_witness_len">witness_len</a>(self: &<a href="bitcoin_types.md#0x3_bitcoin_types_Witness">bitcoin_types::Witness</a>): u64
</code></pre>



<a name="0x3_bitcoin_types_witness_tapscript"></a>

## Function `witness_tapscript`

Get Tapscript following BIP341 rules regarding accounting for an annex.

This does not guarantee that this represents a P2TR [<code><a href="bitcoin_types.md#0x3_bitcoin_types_Witness">Witness</a></code>]. It
merely gets the second to last or third to last element depending on
the first byte of the last element being equal to 0x50. See
bitcoin_script::is_v1_p2tr to check whether this is actually a Taproot witness.


<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_types.md#0x3_bitcoin_types_witness_tapscript">witness_tapscript</a>(self: &<a href="bitcoin_types.md#0x3_bitcoin_types_Witness">bitcoin_types::Witness</a>): <a href="_Option">option::Option</a>&lt;<a href="bitcoin_script_buf.md#0x3_bitcoin_script_buf_ScriptBuf">bitcoin_script_buf::ScriptBuf</a>&gt;
</code></pre>


Expand Down
62 changes: 62 additions & 0 deletions crates/rooch-framework/doc/ord.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

<a name="0x3_ord"></a>

# Module `0x3::ord`



- [Struct `Inscription`](#0x3_ord_Inscription)
- [Function `from_transaction`](#0x3_ord_from_transaction)
- [Function `from_transaction_bytes`](#0x3_ord_from_transaction_bytes)
- [Function `from_witness`](#0x3_ord_from_witness)


<pre><code><b>use</b> <a href="">0x1::option</a>;
<b>use</b> <a href="">0x1::vector</a>;
<b>use</b> <a href="">0x2::bcs</a>;
<b>use</b> <a href="bitcoin_types.md#0x3_bitcoin_types">0x3::bitcoin_types</a>;
</code></pre>



<a name="0x3_ord_Inscription"></a>

## Struct `Inscription`



<pre><code><b>struct</b> <a href="ord.md#0x3_ord_Inscription">Inscription</a> <b>has</b> <b>copy</b>, drop, store
</code></pre>



<a name="0x3_ord_from_transaction"></a>

## Function `from_transaction`



<pre><code><b>public</b> <b>fun</b> <a href="ord.md#0x3_ord_from_transaction">from_transaction</a>(transaction: &<a href="bitcoin_types.md#0x3_bitcoin_types_Transaction">bitcoin_types::Transaction</a>): <a href="">vector</a>&lt;<a href="ord.md#0x3_ord_Inscription">ord::Inscription</a>&gt;
</code></pre>



<a name="0x3_ord_from_transaction_bytes"></a>

## Function `from_transaction_bytes`



<pre><code><b>public</b> <b>fun</b> <a href="ord.md#0x3_ord_from_transaction_bytes">from_transaction_bytes</a>(transaction_bytes: <a href="">vector</a>&lt;u8&gt;): <a href="">vector</a>&lt;<a href="ord.md#0x3_ord_Inscription">ord::Inscription</a>&gt;
</code></pre>



<a name="0x3_ord_from_witness"></a>

## Function `from_witness`



<pre><code><b>public</b> <b>fun</b> <a href="ord.md#0x3_ord_from_witness">from_witness</a>(witness: &<a href="bitcoin_types.md#0x3_bitcoin_types_Witness">bitcoin_types::Witness</a>): <a href="">vector</a>&lt;<a href="ord.md#0x3_ord_Inscription">ord::Inscription</a>&gt;
</code></pre>
46 changes: 43 additions & 3 deletions crates/rooch-framework/sources/bitcoin_types.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// SPDX-License-Identifier: Apache-2.0

module rooch_framework::bitcoin_types{
use rooch_framework::bitcoin_script_buf::{ScriptBuf};
use std::vector;
use std::option::{Self, Option};
use rooch_framework::bitcoin_script_buf::{Self, ScriptBuf};

const LOCK_TIME_THRESHOLD: u32 = 500_000_000;
const TAPROOT_ANNEX_PREFIX: u8 = 0x50;

#[data_struct]
struct Block has store, copy, drop {
Expand Down Expand Up @@ -119,7 +122,7 @@ module rooch_framework::bitcoin_types{
/// Encodable/Decodable, as it is (de)serialized at the end of the full
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other
/// (de)serialization routines.
witness: vector<u8>,
witness: Witness,
}

public fun txin_previous_output(self: &TxIn) : &OutPoint {
Expand All @@ -134,10 +137,47 @@ module rooch_framework::bitcoin_types{
self.sequence
}

public fun txin_witness(self: &TxIn) : &vector<u8> {
public fun txin_witness(self: &TxIn) : &Witness {
&self.witness
}

#[data_struct]
struct Witness has store, copy, drop {
witness: vector<vector<u8>>,
}

public fun witness_nth(self: &Witness, nth: u64) : &vector<u8> {
vector::borrow(&self.witness, nth)
}

public fun witness_len(self: &Witness) : u64 {
vector::length(&self.witness)
}

/// Get Tapscript following BIP341 rules regarding accounting for an annex.
///
/// This does not guarantee that this represents a P2TR [`Witness`]. It
/// merely gets the second to last or third to last element depending on
/// the first byte of the last element being equal to 0x50. See
/// bitcoin_script::is_v1_p2tr to check whether this is actually a Taproot witness.
public fun witness_tapscript(self: &Witness) : Option<ScriptBuf> {
let len = vector::length(&self.witness);
let script_pos_from_last = 2;
let script_buf = option::none<ScriptBuf>();
let idx = 0;
while(idx < len) {
let elem = vector::borrow(&self.witness, idx);
if (idx == len - 1 && len >= 2 && vector::length(elem)>0 && *vector::borrow(elem,0) == TAPROOT_ANNEX_PREFIX) {
script_pos_from_last = 3;
};
if (len >= script_pos_from_last && idx == len - script_pos_from_last) {
option::fill(&mut script_buf, bitcoin_script_buf::new(*elem));
};
idx = idx + 1;
};
script_buf
}

#[data_struct]
struct OutPoint has store, copy, drop {
/// The referenced transaction's txid.
Expand Down
Loading

0 comments on commit 492071d

Please sign in to comment.