Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

feat: add omni lock script extension #468

Open
wants to merge 43 commits into
base: dev-0.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a0d2436
add lock extension module in storage.
EthanYuan Oct 13, 2022
275e6ed
impl get_balance for omni address for the most basic case.
EthanYuan Oct 13, 2022
6ee6713
add global NETWORK_TYPE.
EthanYuan Oct 13, 2022
5005696
fix get_tip_number on dev_chain.
EthanYuan Oct 14, 2022
37a0b9a
refactoring LockScriptHandler.
EthanYuan Oct 17, 2022
12083ff
update dev-chain config
EthanYuan Oct 17, 2022
84a9a56
refactoring integration test.
EthanYuan Oct 18, 2022
b6723a0
add test_get_balance_omni_ethereum
EthanYuan Oct 18, 2022
d5fd637
refactoring.
EthanYuan Oct 19, 2022
234cea6
pass test test_get_balance_by_omni_ethereum.
EthanYuan Oct 20, 2022
79029bc
add test test_get_balance_by_omni_secp
EthanYuan Oct 20, 2022
f8edd2f
add tests:
EthanYuan Oct 21, 2022
ac35ce9
add generate_extra_filter for LockScriptHandler.
EthanYuan Oct 25, 2022
73c997b
pass test test_omni_secp_transfer_ckb
EthanYuan Oct 28, 2022
340b9c5
refactoring signer mod.
EthanYuan Oct 31, 2022
a567c69
add test test_omni_eth_transfer_ckb
EthanYuan Nov 1, 2022
14378a2
impl adjust account increase.
EthanYuan Nov 2, 2022
1f3ba61
refactoring.
EthanYuan Nov 2, 2022
04e9c89
test test_adjust_account_omni pass.
EthanYuan Nov 3, 2022
3bb8836
pass test test_transfer_udt_to_omni_acp.
EthanYuan Nov 3, 2022
be82295
pass test test_transfer_ckb_to_omni_acp.
EthanYuan Nov 3, 2022
9419b40
refactoring: lock_filter use HashSet.
EthanYuan Nov 5, 2022
4509b01
refactoring: define LockFilter.
EthanYuan Nov 5, 2022
005fff7
refactoring get_script_by_address.
EthanYuan Nov 7, 2022
d71ccbc
pass test test_omni_transfer_ckb_from_acp_to_acp.
EthanYuan Nov 7, 2022
357e18d
refactoring pw lock.
EthanYuan Nov 7, 2022
9adb771
refactoring CkbCellsCache.
EthanYuan Nov 7, 2022
9a0509a
refactoring: rm AcpCellsCache
EthanYuan Nov 8, 2022
ede71ef
refactoring dao claim.
EthanYuan Nov 8, 2022
5ac212a
add test test_omni_transfer_ckb_change
EthanYuan Nov 8, 2022
cbd62a6
refacotring: rm PoolUdtPriority::PwLockEthereum
EthanYuan Nov 8, 2022
3853ebb
add test test_pw_transfer_udt_to_provide_capacity.
EthanYuan Nov 8, 2022
df17c4e
pass test_omni_transfer_udt_to_provide_capacity and test_omni_transfe…
EthanYuan Nov 8, 2022
796d923
impl omni's is_mode_supported.
EthanYuan Nov 9, 2022
5a5f903
refactoring test.
EthanYuan Nov 9, 2022
9b3af33
refactoring: keep in one source code file.
EthanYuan Nov 9, 2022
4a7404f
refactor utils methods
EthanYuan Nov 9, 2022
4a61cfa
pass omni dao tests.
EthanYuan Nov 10, 2022
57dabda
add tests:
EthanYuan Nov 10, 2022
fc6f11e
pass test test_omni_issue_udt_from_multi_item.
EthanYuan Nov 10, 2022
5a95c44
pass test for rpc get_account_info
EthanYuan Nov 10, 2022
9185af8
pass test
EthanYuan Nov 10, 2022
db984dc
refactoring.
EthanYuan Nov 10, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
396 changes: 334 additions & 62 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ members = [
"core/synchronization",

"db/db-sqlx",
"db/xsql-test"
"db/xsql-test",

"extension-lock"
]

[profile.release]
Expand Down
49 changes: 47 additions & 2 deletions common/src/lazy.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,54 @@
use crate::utils::ScriptInfo;

use ckb_types::H256;
use once_cell::sync::OnceCell;

use std::collections::HashMap;

// built-in locks
pub static SECP256K1_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static SUDT_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static ACP_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static PW_LOCK_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static CHEQUE_CODE_HASH: OnceCell<H256> = OnceCell::new();

// built-in types
pub static SUDT_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static DAO_CODE_HASH: OnceCell<H256> = OnceCell::new();
pub static PW_LOCK_CODE_HASH: OnceCell<H256> = OnceCell::new();

// These EXTENSION prefixed variables are depended on by extension lock scripts.
// Considering compatibility, please be careful if you need to modify them.
pub static EXTENSION_LOCK_SCRIPT_NAMES: OnceCell<HashMap<H256, String>> = OnceCell::new();
pub static EXTENSION_LOCK_SCRIPT_INFOS: OnceCell<HashMap<String, ScriptInfo>> = OnceCell::new();

pub fn is_secp_script(code_hash: &H256) -> bool {
code_hash
== SECP256K1_CODE_HASH
.get()
.expect("get built-in secp lock code hash")
}

pub fn is_acp_script(code_hash: &H256) -> bool {
code_hash == ACP_CODE_HASH.get().expect("get built-in acp code hash")
}

pub fn is_pw_lock_script(code_hash: &H256) -> bool {
code_hash
== PW_LOCK_CODE_HASH
.get()
.expect("get built-in pw lock code hash")
}

pub fn is_cheque_script(code_hash: &H256) -> bool {
code_hash
== CHEQUE_CODE_HASH
.get()
.expect("get built-in cheque code hash")
}

pub fn is_sudt_script(code_hash: &H256) -> bool {
code_hash == SUDT_CODE_HASH.get().expect("get sudt code hash")
}

pub fn is_dao_script(code_hash: &H256) -> bool {
code_hash == DAO_CODE_HASH.get().expect("get dao code hash")
}
2 changes: 0 additions & 2 deletions core/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ edition = "2021"

[dependencies]
ansi_term = "0.12"
ckb-types = "0.104"
ckb-jsonrpc-types = "0.104"
clap = "2.34"
log = "0.4"
log4rs = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["time"] }
Expand Down
35 changes: 33 additions & 2 deletions core/cli/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use common::{utils::ScriptInfo, Result};

use ckb_jsonrpc_types::{CellDep, Script};
use common::lazy::{EXTENSION_LOCK_SCRIPT_INFOS, EXTENSION_LOCK_SCRIPT_NAMES};
use common::{utils::ScriptInfo, Result};
use serde::{de::DeserializeOwned, Deserialize};

use std::{collections::HashMap, fs::File, io::Read, path::Path};
Expand Down Expand Up @@ -94,6 +94,7 @@ pub struct MercuryConfig {
pub network_config: NetworkConfig,
pub sync_config: SyncConfig,
pub builtin_scripts: Vec<ScriptConfig>,
pub extension_scripts: Vec<ScriptConfig>,

#[serde(default = "default_need_sync")]
pub allow_parallel_sync: bool,
Expand Down Expand Up @@ -130,6 +131,36 @@ impl MercuryConfig {
}

pub fn to_script_map(&self) -> HashMap<String, ScriptInfo> {
let extension_script_names = self
.extension_scripts
.iter()
.map(|s| {
let script: Script =
serde_json::from_str::<Script>(&s.script).expect("config string to script");
(script.code_hash, s.script_name.clone())
})
.collect();
let _ = EXTENSION_LOCK_SCRIPT_NAMES.set(extension_script_names);

let extension_script_infos = self
.extension_scripts
.iter()
.map(|s| {
(
s.script_name.clone(),
ScriptInfo {
script: serde_json::from_str::<Script>(&s.script)
.expect("config string to script")
.into(),
cell_dep: serde_json::from_str::<CellDep>(&s.cell_dep)
.expect("config string to cell dep")
.into(),
},
)
})
.collect();
let _ = EXTENSION_LOCK_SCRIPT_INFOS.set(extension_script_infos);

self.builtin_scripts
.iter()
.map(|s| {
Expand Down
1 change: 1 addition & 0 deletions core/rpc/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ common = { path = "../../../common" }
core-ckb-client = { path = "../../ckb-client" }
core-rpc-types = { path = "../types" }
core-storage = { path = "../../storage" }
extension-lock = { path = "../../../extension-lock" }

[dev-dependencies]
env_logger = "0.9"
Expand Down
5 changes: 4 additions & 1 deletion core/rpc/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ pub enum CoreError {

#[display(fmt = "When issuing udt from items must contain owner item")]
FromNotContainOwner,

#[display(fmt = "Cannot find lock script by item")]
CannotFindLockScriptByItem,
}

impl RpcError for CoreError {
Expand Down Expand Up @@ -172,13 +175,13 @@ impl RpcError for CoreError {
CoreError::ItemsNotSameEnumValue => -11023,
CoreError::UnsupportIdentityFlag => -11024,
CoreError::AmountMustPositive => -11025,

CoreError::UnsupportAddress => -11026,
CoreError::InvalidTxPrebuilt(_) => -11027,
CoreError::CkbClientError(_) => -11028,
CoreError::CkbIsNotEnough(_) => -11029,
CoreError::UDTIsNotEnough(_) => -11030,
CoreError::UnsupportTransferMode(_) => -11031,
CoreError::CannotFindLockScriptByItem => -11032,

CoreError::MissingConsumedInfo => -10020,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use crate::r#impl::utils::map_json_items;
use crate::r#impl::utils::{calculate_cell_capacity, map_json_items};
use crate::r#impl::{calculate_tx_size, utils, utils_types::TransferComponents};
use crate::{error::CoreError, InnerResult, MercuryRpcImpl};

use ckb_types::core::TransactionView;
use ckb_types::{bytes::Bytes, packed, prelude::*, H256};
use common::address::{is_acp, is_pw_lock};
use ckb_types::core::{Capacity, TransactionView};
use ckb_types::packed::{self, Script};
use ckb_types::{bytes::Bytes, prelude::*, H256};
use common::hash::blake2b_256_to_160;
use common::lazy::{ACP_CODE_HASH, PW_LOCK_CODE_HASH, SECP256K1_CODE_HASH};
use common::utils::decode_udt_amount;
use common::lazy::{
is_acp_script, is_pw_lock_script, ACP_CODE_HASH, PW_LOCK_CODE_HASH, SECP256K1_CODE_HASH,
};
use common::utils::{decode_udt_amount, encode_udt_amount};
use common::{DetailedCell, PaginationRequest, ACP, PW_LOCK, SECP256K1, SUDT};
use core_ckb_client::CkbRpc;
use core_rpc_types::consts::{ckb, DEFAULT_FEE_RATE, STANDARD_SUDT_CAPACITY};
use core_rpc_types::consts::{ckb, DEFAULT_FEE_RATE};
use core_rpc_types::{
AccountType, AdjustAccountPayload, AssetType, GetAccountInfoPayload, GetAccountInfoResponse,
Item, ScriptGroup, TransactionCompletionResponse,
AdjustAccountPayload, AssetType, GetAccountInfoPayload, GetAccountInfoResponse, Item,
LockFilter, ScriptGroup, TransactionCompletionResponse,
};
use extension_lock::LockScriptHandler;

use std::collections::{BTreeSet, HashSet};
use std::collections::{BTreeSet, HashMap, HashSet};
use std::convert::TryInto;

impl<C: CkbRpc> MercuryRpcImpl<C> {
Expand All @@ -31,27 +34,18 @@ impl<C: CkbRpc> MercuryRpcImpl<C> {

let account_number = payload.account_number.map(Into::into).unwrap_or(1) as usize;
let fee_rate = payload.fee_rate.map(Into::into).unwrap_or(DEFAULT_FEE_RATE);

let item: Item = payload.item.clone().try_into()?;
let acp_address = self.get_acp_address_by_item(&item).await?;
let lock_filter = if is_acp(&acp_address) {
ACP_CODE_HASH.get()
} else if is_pw_lock(&acp_address) {
PW_LOCK_CODE_HASH.get()
} else {
return Err(CoreError::UnsupportAddress.into());
};

let identity_item = Item::Identity(self.address_to_identity(&acp_address.to_string())?);
let mut asset_set = HashSet::new();
asset_set.insert(payload.asset_info.clone());

let live_acps = self
.get_live_cells_by_item(
identity_item.clone(),
Item::Address(acp_address.to_string()),
asset_set,
None,
None,
lock_filter,
&HashMap::new(),
None,
&mut PaginationRequest::default(),
)
Expand Down Expand Up @@ -108,10 +102,17 @@ impl<C: CkbRpc> MercuryRpcImpl<C> {
let sudt_type_script = self
.build_sudt_type_script(blake2b_256_to_160(&payload.asset_info.udt_hash))
.await?;

let type_script_opt = Some(sudt_type_script.clone()).pack();
for _i in 0..acp_need_count {
let capacity = calculate_cell_capacity(
&lock_script,
&type_script_opt,
Capacity::bytes(Bytes::from(encode_udt_amount(0)).len())
.expect("generate capacity"),
);

utils::build_cell_for_output(
STANDARD_SUDT_CAPACITY + extra_ckb,
capacity + extra_ckb,
lock_script.clone(),
Some(sudt_type_script.clone()),
Some(0),
Expand Down Expand Up @@ -160,10 +161,11 @@ impl<C: CkbRpc> MercuryRpcImpl<C> {
} else if self.is_script(&output.cell_output.lock(), PW_LOCK)? {
output.cell_output.lock()
} else {
return Err(CoreError::UnsupportLockScript(hex::encode(
output.cell_output.lock().code_hash().as_slice(),
))
.into());
let lock = output.cell_output.lock();
let lock_code_hash = lock.code_hash();
LockScriptHandler::get_normal_script(lock).ok_or_else(|| {
CoreError::UnsupportLockScript(hex::encode(lock_code_hash.as_slice()))
})?
};
let type_script: Option<packed::Script> = None;
let cell = output
Expand Down Expand Up @@ -220,6 +222,7 @@ impl<C: CkbRpc> MercuryRpcImpl<C> {
script_deps.insert(SECP256K1.to_string());
script_deps.insert(PW_LOCK.to_string());
}
LockScriptHandler::insert_script_deps(&lock_code_hash, &mut script_deps);

let mut transfer_components = TransferComponents::new();
transfer_components.inputs = inputs;
Expand All @@ -243,29 +246,49 @@ impl<C: CkbRpc> MercuryRpcImpl<C> {
) -> InnerResult<GetAccountInfoResponse> {
let item: Item = payload.item.clone().try_into()?;
let acp_address = self.get_acp_address_by_item(&item).await?;
let (lock_filter, account_type) = if is_acp(&acp_address) {
(ACP_CODE_HASH.get(), AccountType::Acp)
} else if is_pw_lock(&acp_address) {
(PW_LOCK_CODE_HASH.get(), AccountType::PwLock)
} else {
return Err(CoreError::UnsupportAddress.into());
};

let identity_item = Item::Identity(self.address_to_identity(&acp_address.to_string())?);
let mut lock_filters = HashMap::new();
lock_filters.insert(
ACP_CODE_HASH.get().expect("get built-in acp hash code"),
LockFilter::default(),
);
lock_filters.insert(
PW_LOCK_CODE_HASH
.get()
.expect("get built-in pw lock hash code"),
LockFilter::default(),
);
LockScriptHandler::get_can_be_pooled_ckb_lock(
&mut lock_filters,
LockFilter { is_acp: Some(true) },
);

let mut asset_set = HashSet::new();
asset_set.insert(payload.asset_info.clone());
let live_acps = self
.get_live_cells_by_item(
identity_item.clone(),
Item::Address(acp_address.to_string()),
asset_set,
None,
None,
lock_filter,
&lock_filters,
None,
&mut PaginationRequest::default(),
)
.await?;

let script: Script = acp_address.payload().into();
let code_hash = script.code_hash().unpack();
let account_type = if is_acp_script(&code_hash) {
"Acp".to_string()
} else if is_pw_lock_script(&code_hash) {
"PwLock".to_string()
} else {
LockScriptHandler::get_script_name(&code_hash)
.map(|x| x.to_owned())
.ok_or(CoreError::UnsupportAddress)?
};

Ok(GetAccountInfoResponse {
account_number: (live_acps.len() as u32).into(),
account_address: acp_address.to_string(),
Expand Down
Loading