Skip to content

Commit

Permalink
merged with master
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolasHai committed Sep 30, 2024
2 parents 91af4e3 + e57a4d3 commit af57995
Show file tree
Hide file tree
Showing 41 changed files with 527 additions and 360 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ go_deps.bzl @dfinity/idx
/packages/icrc-ledger-types/ @dfinity/finint
/packages/ic-ledger-hash-of/ @dfinity/finint
/packages/pocket-ic/ @dfinity/pocket-ic
/packages/ic-ethereum-types/ @dfinity/cross-chain-team
/packages/ic-sha3/ @dfinity/crypto-team
/packages/ic-signature-verification/ @dfinity/crypto-team
/packages/ic-vetkd-utils/ @dfinity/crypto-team
Expand Down
7 changes: 4 additions & 3 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"packages/icrc-ledger-client",
"packages/icrc-ledger-client-cdk",
"packages/icrc-ledger-types",
"packages/ic-ethereum-types",
"packages/ic-sha3",
"packages/ic-ledger-hash-of",
"packages/ic-signature-verification",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
load("@rules_rust//rust:defs.bzl", "rust_doc", "rust_doc_test", "rust_library", "rust_test")

package(default_visibility = ["//visibility:public"])

Expand All @@ -17,24 +17,25 @@ DEV_DEPENDENCIES = [
"@crate_index//:serde_json",
]

MACRO_DEPENDENCIES = []

DEV_MACRO_DEPENDENCIES = []

ALIASES = {}

rust_library(
name = "types",
name = "ic-ethereum-types",
srcs = glob(["src/**/*.rs"]),
aliases = ALIASES,
crate_name = "ic_ethereum_types",
proc_macro_deps = MACRO_DEPENDENCIES,
deps = DEPENDENCIES,
)

rust_test(
name = "types_test",
crate = ":types",
proc_macro_deps = DEV_MACRO_DEPENDENCIES,
name = "unit_tests",
crate = ":ic-ethereum-types",
deps = DEV_DEPENDENCIES,
)

rust_doc(
name = "doc",
crate = ":ic-ethereum-types",
)

rust_doc_test(
name = "doc_test",
crate = ":ic-ethereum-types",
deps = [":ic-ethereum-types"] + DEPENDENCIES + DEV_DEPENDENCIES,
)
13 changes: 13 additions & 0 deletions packages/ic-ethereum-types/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2024-09-30

### Added

- `ic_ethereum_types::Address`: An Ethereum address of 20 bytes.
- `ic_ethereum_types::serde_data`: Serialize and deserialize any hexadecimal type following Ethereum's format (prefixed with `0x`).
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
[package]
name = "ic-ethereum-types"
description = "Ethereum common types that are used across multiple crates"
version.workspace = true
version = "1.0.0"
description = "Ethereum common types that by canisters on the Internet Computer"
license = "Apache-2.0"
readme = "README.md"
include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"]
repository = "https://github.com/dfinity/ic"
authors.workspace = true
edition.workspace = true
documentation.workspace = true
documentation = "https://docs.rs/ic-ethereum-types"

[dependencies]
hex = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions packages/ic-ethereum-types/LICENSE
3 changes: 3 additions & 0 deletions packages/ic-ethereum-types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# IC Ethereum Types

Ethereum types for canisters on the Internet Computer.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ use std::fmt::{Formatter, LowerHex, UpperHex};
use std::str::FromStr;

/// An Ethereum account address.
///
/// # Examples
///
/// Parse an address from a string:
/// ```
/// use std::str::FromStr;
/// let address = ic_ethereum_types::Address::from_str("0x7a250d5630b4cf539739df2c5dacb4c659f2488d").unwrap();
/// assert_eq!(address.into_bytes(), [0x7a, 0x25, 0x0d, 0x56, 0x30, 0xb4, 0xcf, 0x53, 0x97, 0x39, 0xdf, 0x2c, 0x5d, 0xac, 0xb4, 0xc6, 0x59, 0xf2, 0x48, 0x8d]);
/// ```
///
/// Instantiate an address from raw bytes:
/// ```
/// let address = ic_ethereum_types::Address::new([0x7a, 0x25, 0x0d, 0x56, 0x30, 0xb4, 0xcf, 0x53, 0x97, 0x39, 0xdf, 0x2c, 0x5d, 0xac, 0xb4, 0xc6, 0x59, 0xf2, 0x48, 0x8d]);
/// assert_eq!(address.to_string(), "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D");
/// ```
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Decode, Deserialize, Encode, Serialize,
)]
Expand All @@ -26,12 +41,21 @@ impl AsRef<[u8]> for Address {
}

impl Address {
/// Ethereum zero address.
///
/// ```
/// let address = ic_ethereum_types::Address::ZERO;
/// assert_eq!(address.to_string(), "0x0000000000000000000000000000000000000000");
/// assert_eq!(address.into_bytes(), [0u8; 20]);
/// ```
pub const ZERO: Self = Self([0u8; 20]);

/// Create a new Ethereum address from raw bytes.
pub const fn new(bytes: [u8; 20]) -> Self {
Self(bytes)
}

/// Convert an Ethereum address into a 20-byte array.
pub const fn into_bytes(self) -> [u8; 20] {
self.0
}
Expand All @@ -49,6 +73,7 @@ impl UpperHex for Address {
}
}

/// Parse an address from a 32-byte array with left zero padding.
impl TryFrom<&[u8; 32]> for Address {
type Error = String;

Expand All @@ -66,7 +91,7 @@ impl TryFrom<&[u8; 32]> for Address {
}
}

// Converting from 20-byte address to 32-byte, with left zero padding.
/// Convert a 20-byte address to 32-byte array, with left zero padding.
impl From<&Address> for [u8; 32] {
fn from(address: &Address) -> Self {
let bytes = address.as_ref();
Expand Down Expand Up @@ -97,10 +122,9 @@ impl fmt::Debug for Address {
}
}

/// Display address using [EIP-55](https://eips.ethereum.org/EIPS/eip-55).
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Display address using EIP-55
// https://eips.ethereum.org/EIPS/eip-55
let mut addr_chars = [0u8; 20 * 2];
hex::encode_to_slice(self.0, &mut addr_chars)
.expect("bug: failed to encode an address as hex");
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions packages/ic-ethereum-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Ethereum types used by canisters on the Internet Computer.

#![forbid(unsafe_code)]
#![warn(rust_2018_idioms)]
#![forbid(missing_docs)]
#![warn(future_incompatible)]

mod address;
pub mod serde_data;

pub use address::Address;
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Serde serialization and deserialization for Ethereum hexadecimal types (prefixed by `0x`).

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -35,7 +37,7 @@ where
{
type Value = T;

fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "a hex-encoded DATA string")
}

Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions rs/bitcoin/kyt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ rust_library(
# Keep sorted.
"@crate_index//:bitcoin_0_32",
"@crate_index//:candid",
"@crate_index//:ciborium",
"@crate_index//:futures",
"@crate_index//:ic-btc-interface",
"@crate_index//:ic-cdk",
"@crate_index//:ic-stable-structures",
"@crate_index//:serde",
],
)
Expand Down
2 changes: 2 additions & 0 deletions rs/bitcoin/kyt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ path = "src/main.rs"
[dependencies]
bitcoin = { version = "0.32.2", default-features = false }
candid = { workspace = true }
ciborium = { workspace = true }
futures = { workspace = true }
ic-btc-interface = { workspace = true }
ic-cdk = { workspace = true }
ic-stable-structures = { workspace = true }
serde = { workspace = true }

[dev-dependencies]
Expand Down
18 changes: 17 additions & 1 deletion rs/bitcoin/kyt/btc_kyt_canister.did
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,23 @@ type CheckTransactionIrrecoverableError = variant {
InvalidTransaction : text;
};

service : {
type InitArg = record {
btc_network : BtcNetwork
};

type UpgradeArg = record {};

type KytArg = variant {
InitArg : InitArg;
UpgradeArg: opt UpgradeArg;
};

type BtcNetwork = variant {
mainnet;
testnet
};

service : (KytArg) -> {
// Check input addresses of a transaction matching the given transaction id.
// See `CheckTransactionResponse` for more details on the return result.
//
Expand Down
7 changes: 5 additions & 2 deletions rs/bitcoin/kyt/src/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::types::{
CheckTransactionStatus,
};
use crate::{blocklist_contains, state};
use bitcoin::{address::FromScriptError, Address, Network, Transaction};
use bitcoin::{address::FromScriptError, Address, Transaction};
use futures::future::try_join_all;
use ic_btc_interface::Txid;
use std::convert::Infallible;
Expand Down Expand Up @@ -250,5 +250,8 @@ pub trait FetchEnv {

fn transaction_output_address(tx: &Transaction, vout: u32) -> Result<Address, FromScriptError> {
let output = &tx.output[vout as usize];
Address::from_script(&output.script_pubkey, Network::Bitcoin)
Address::from_script(
&output.script_pubkey,
bitcoin::Network::from(state::get_config().btc_network),
)
}
4 changes: 4 additions & 0 deletions rs/bitcoin/kyt/src/fetch/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::blocklist;
use crate::types::BtcNetwork;
use bitcoin::{
absolute::LockTime, hashes::Hash, transaction::Version, Amount, OutPoint, PubkeyHash,
ScriptBuf, Sequence, Transaction, TxIn, TxOut, Witness,
Expand Down Expand Up @@ -256,6 +257,9 @@ async fn test_fetch_tx() {
#[tokio::test]
async fn test_check_fetched() {
let mut env = MockEnv::new(CHECK_TRANSACTION_CYCLES_REQUIRED);
state::set_config(state::Config {
btc_network: BtcNetwork::Mainnet,
});
let good_address = Address::from_str("12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S")
.unwrap()
.assume_checked();
Expand Down
35 changes: 5 additions & 30 deletions rs/bitcoin/kyt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use bitcoin::{consensus::Decodable, Address, Transaction};
use ic_btc_interface::Txid;
use ic_cdk::api::call::RejectionCode;
use ic_cdk::api::management_canister::http_request::{
http_request, CanisterHttpRequestArgument, HttpHeader, HttpMethod, TransformContext,
TransformFunc,
};
use ic_cdk::api::management_canister::http_request::http_request;

pub mod blocklist;
mod fetch;
mod providers;
mod state;
mod types;

Expand All @@ -16,6 +14,7 @@ pub use fetch::{
INITIAL_MAX_RESPONSE_BYTES,
};
use fetch::{FetchEnv, FetchResult, TryFetchResult};
pub use state::{get_config, set_config, Config};
use state::{FetchGuardError, HttpGetTxError};
pub use types::*;

Expand Down Expand Up @@ -62,32 +61,8 @@ impl FetchEnv for KytCanisterEnv {
max_response_bytes: u32,
) -> Result<Transaction, HttpGetTxError> {
// TODO(XC-159): Support multiple providers
let host = "btcscan.org";
let url = format!("https://{}/api/tx/{}/raw", host, txid);
let request_headers = vec![
HttpHeader {
name: "Host".to_string(),
value: format!("{host}:443"),
},
HttpHeader {
name: "User-Agent".to_string(),
value: "bitcoin_inputs_collector".to_string(),
},
];
let request = CanisterHttpRequestArgument {
url: url.to_string(),
method: HttpMethod::GET,
body: None,
max_response_bytes: Some(max_response_bytes as u64),
transform: Some(TransformContext {
function: TransformFunc(candid::Func {
principal: ic_cdk::api::id(),
method: "transform".to_string(),
}),
context: vec![],
}),
headers: request_headers,
};
let request = providers::create_request(get_config().btc_network, txid, max_response_bytes);
let url = request.url.clone();
let cycles = get_tx_cycle_cost(max_response_bytes);
match http_request(request, cycles).await {
Ok((response,)) => {
Expand Down
Loading

0 comments on commit af57995

Please sign in to comment.