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

Commit

Permalink
Merge pull request #118 from zeroqn/feat-change-ckb-decimal-to-18
Browse files Browse the repository at this point in the history
BREAKING CHANGE: change ckb decimal to 18
  • Loading branch information
Flouse committed May 7, 2022
2 parents a23886b + 7611073 commit 03011e0
Show file tree
Hide file tree
Showing 33 changed files with 1,173 additions and 216 deletions.
472 changes: 439 additions & 33 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
members = [
"tests",
"c-uint256-tests",
]
16 changes: 16 additions & 0 deletions c-uint256-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "c-uint256-tests"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cty = "0.2"

[dev-dependencies]
proptest = "1.0"
primitive-types = { version = "0.10", default-features = false, features = [ "impl-serde", "impl-rlp" ] }

[build-dependencies]
cc = "1.0"
20 changes: 20 additions & 0 deletions c-uint256-tests/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
fn main() {
let mut build = cc::Build::new();

// building
build
.file("../c/rust-binding/uint256_wrapper.c")
.static_flag(true)
.flag("-O3")
.flag("-Wl,-static")
.flag("-Wl,--gc-sections")
.include("../c/")
.flag("-Wall")
.flag("-Werror")
.flag("-Wno-unused-parameter")
.flag("-Wno-nonnull")
.flag("-Wno-nonnull-compare")
.flag("-Wno-unused-function")
.define("__SHARED_LIBRARY__", None)
.compile("c-uint256.a");
}
11 changes: 11 additions & 0 deletions c-uint256-tests/loop_proptest
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

export PROPTEST_CASES=100000

counter=1
while :
do
echo "$counter round"
cargo test
((counter++))
done
168 changes: 168 additions & 0 deletions c-uint256-tests/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* automatically generated by rust-bindgen 0.59.2 */

pub const true_: u32 = 1;
pub const false_: u32 = 0;
pub const INT8_MIN: i32 = -128;
pub const INT16_MIN: i32 = -32768;
pub const INT32_MIN: i32 = -2147483648;
pub const INT64_MIN: i64 = -9223372036854775808;
pub const INT8_MAX: u32 = 127;
pub const INT16_MAX: u32 = 32767;
pub const INT32_MAX: u32 = 2147483647;
pub const INT64_MAX: u64 = 9223372036854775807;
pub const UINT8_MAX: u32 = 255;
pub const UINT16_MAX: u32 = 65535;
pub const UINT32_MAX: u32 = 4294967295;
pub const UINT64_MAX: i32 = -1;
pub const SIZE_MAX: i32 = -1;
pub type size_t = ::std::os::raw::c_ulong;
pub type ssize_t = ::std::os::raw::c_long;
extern "C" {
pub fn memset(
dest: *mut ::std::os::raw::c_void,
c: ::std::os::raw::c_int,
n: ::std::os::raw::c_ulong,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn memcpy(
dest: *mut ::std::os::raw::c_void,
src: *const ::std::os::raw::c_void,
n: ::std::os::raw::c_ulong,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn memcmp(
vl: *const ::std::os::raw::c_void,
vr: *const ::std::os::raw::c_void,
n: ::std::os::raw::c_ulong,
) -> ::std::os::raw::c_int;
}
pub type WT = size_t;
extern "C" {
pub fn memmove(
dest: *mut ::std::os::raw::c_void,
src: *const ::std::os::raw::c_void,
n: ::std::os::raw::c_ulong,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn strcpy(
d: *mut ::std::os::raw::c_char,
s: *const ::std::os::raw::c_char,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn strlen(s: *const ::std::os::raw::c_char) -> ::std::os::raw::c_ulong;
}
extern "C" {
pub fn strcmp(
l: *const ::std::os::raw::c_char,
r: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn malloc(size: ::std::os::raw::c_ulong) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn free(ptr: *mut ::std::os::raw::c_void);
}
extern "C" {
pub fn calloc(
nmemb: ::std::os::raw::c_ulong,
size: ::std::os::raw::c_ulong,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn realloc(
ptr: *mut ::std::os::raw::c_void,
size: ::std::os::raw::c_ulong,
) -> *mut ::std::os::raw::c_void;
}
pub type cmpfun = ::std::option::Option<
unsafe extern "C" fn(
arg1: *const ::std::os::raw::c_void,
arg2: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>;
extern "C" {
pub fn qsort(base: *mut ::std::os::raw::c_void, nel: size_t, width: size_t, cmp: cmpfun);
}
extern "C" {
pub fn bsearch(
key: *const ::std::os::raw::c_void,
base: *const ::std::os::raw::c_void,
nel: size_t,
width: size_t,
cmp: ::std::option::Option<
unsafe extern "C" fn(
arg1: *const ::std::os::raw::c_void,
arg2: *const ::std::os::raw::c_void,
) -> ::std::os::raw::c_int,
>,
) -> *mut ::std::os::raw::c_void;
}
extern "C" {
pub fn printf(format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn _start();
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct uint256_t {
pub array: [u32; 8usize],
}
#[test]
fn bindgen_test_layout_uint256_t() {
assert_eq!(
::std::mem::size_of::<uint256_t>(),
32usize,
concat!("Size of: ", stringify!(uint256_t))
);
assert_eq!(
::std::mem::align_of::<uint256_t>(),
4usize,
concat!("Alignment of ", stringify!(uint256_t))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<uint256_t>())).array as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(uint256_t),
"::",
stringify!(array)
)
);
}
extern "C" {
pub fn gw_uint256_zero(num: *mut uint256_t);
}
extern "C" {
pub fn gw_uint256_one(num: *mut uint256_t);
}
extern "C" {
pub fn gw_uint256_max(num: *mut uint256_t);
}
extern "C" {
pub fn gw_uint256_overflow_add(
a: uint256_t,
b: uint256_t,
sum: *mut uint256_t,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn gw_uint256_underflow_sub(
a: uint256_t,
b: uint256_t,
rem: *mut uint256_t,
) -> ::std::os::raw::c_int;
}
pub const GW_UINT256_SMALLER: ::std::os::raw::c_int = -1;
pub const GW_UINT256_EQUAL: ::std::os::raw::c_int = 0;
pub const GW_UINT256_LARGER: ::std::os::raw::c_int = 1;
pub type _bindgen_ty_1 = ::std::os::raw::c_int;
extern "C" {
pub fn gw_uint256_cmp(a: uint256_t, b: uint256_t) -> ::std::os::raw::c_int;
}
162 changes: 162 additions & 0 deletions c-uint256-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use std::cmp::Ordering;

use self::bindings::{
gw_uint256_cmp, gw_uint256_one, gw_uint256_overflow_add, gw_uint256_underflow_sub, uint256_t,
GW_UINT256_EQUAL, GW_UINT256_LARGER, GW_UINT256_SMALLER,
};

// deref_nullptr in test code `fn bindgen_test_layout_uint256_t()`.
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(deref_nullptr)]
mod bindings;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct U256(uint256_t);

impl U256 {
pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
let mut array = [0u32; 8];
for i in 0..8 {
let start = i * 4;
let end = i * 4 + 4;
let u32_val = u32::from_le_bytes(bytes[start..end].try_into().unwrap());
array[i] = u32_val;
}
U256(uint256_t { array })
}

pub fn to_le_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
for i in 0..8 {
let u32_val = self.0.array[i];
let start = i * 4;
let end = i * 4 + 4;
bytes[start..end].copy_from_slice(&u32_val.to_le_bytes());
}

bytes
}

pub fn zero() -> Self {
U256(uint256_t { array: [0u32; 8] })
}

pub fn one() -> Self {
let mut val = Self::zero();
unsafe { gw_uint256_one(&mut val.0) };

val
}

pub fn checked_add(&self, other: U256) -> Option<U256> {
let mut sum = U256::zero();
match unsafe { gw_uint256_overflow_add(self.0, other.0, &mut sum.0) } {
0 => Some(sum),
_err => None,
}
}

pub fn checked_sub(&self, other: U256) -> Option<U256> {
let mut rem = U256::zero();
match unsafe { gw_uint256_underflow_sub(self.0, other.0, &mut rem.0) } {
0 => Some(rem),
_err => None,
}
}
}

impl PartialOrd for U256 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match unsafe { gw_uint256_cmp(self.0, other.0) } {
GW_UINT256_SMALLER => Some(Ordering::Less),
GW_UINT256_EQUAL => Some(Ordering::Equal),
GW_UINT256_LARGER => Some(Ordering::Greater),
_ => None,
}
}
}

impl Ord for U256 {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}

#[cfg(test)]
mod tests {
use super::U256 as CU256;
use primitive_types::U256 as PU256;
use proptest::prelude::*;

impl PartialEq<PU256> for CU256 {
fn eq(&self, other: &PU256) -> bool {
let mut other_le_bytes = [0u8; 32];
other.to_little_endian(&mut other_le_bytes);

self.to_le_bytes() == other_le_bytes
}
}

impl CU256 {
fn into_pu256(self) -> PU256 {
PU256::from_little_endian(&self.to_le_bytes())
}
}

#[test]
fn test_c_uint256_one() {
let one = CU256::one();
assert_eq!(one.checked_sub(one), Some(CU256::zero()));

let p_one = PU256::one();
assert_eq!(one, p_one);
}

proptest! {
#[test]
fn test_c_uint256_checked_add(
a in prop::array::uniform32(any::<u8>()),
b in prop::array::uniform32(any::<u8>())
) {
let ca = CU256::from_le_bytes(a);
let cb = CU256::from_le_bytes(b);
let csum = ca.checked_add(cb);

let pa = PU256::from_little_endian(&a);
let pb = PU256::from_little_endian(&b);
let psum = pa.checked_add(pb);
prop_assert_eq!(csum.map(CU256::into_pu256), psum);
}

#[test]
fn test_c_uint256_checked_sub(
a in prop::array::uniform32(any::<u8>()),
b in prop::array::uniform32(any::<u8>())
) {
let ca = CU256::from_le_bytes(a);
let cb = CU256::from_le_bytes(b);
let crem = ca.checked_sub(cb);

let pa = PU256::from_little_endian(&a);
let pb = PU256::from_little_endian(&b);
let prem = pa.checked_sub(pb);
prop_assert_eq!(crem.map(CU256::into_pu256), prem);
}

#[test]
fn test_c_uint256_cmp(
a in prop::array::uniform32(any::<u8>()),
b in prop::array::uniform32(any::<u8>())
) {
let ca = CU256::from_le_bytes(a);
let cb = CU256::from_le_bytes(b);

let pa = PU256::from_little_endian(&a);
let pb = PU256::from_little_endian(&b);

prop_assert_eq!(ca > cb, pa > pb);
}
}
}
Loading

0 comments on commit 03011e0

Please sign in to comment.