diff --git a/.gitmodules b/.gitmodules index b0c8ac4..2c177d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,13 @@ -[submodule "deps/ckb-c-stdlib-20210801"] - path = deps/ckb-c-stdlib-20210801 - url = https://github.com/nervosnetwork/ckb-c-stdlib.git - branch = master [submodule "deps/sparse-merkle-tree"] path = deps/sparse-merkle-tree url = https://github.com/nervosnetwork/sparse-merkle-tree.git branch = master -[submodule "deps/secp256k1-20210801"] - path = deps/secp256k1-20210801 +[submodule "deps/ckb-c-stdlib"] + path = deps/ckb-c-stdlib + url = https://github.com/nervosnetwork/ckb-c-stdlib.git +[submodule "deps/secp256k1"] + path = deps/secp256k1 url = https://github.com/nervosnetwork/secp256k1.git - branch = schnorr +[submodule "deps/ed25519"] + path = deps/ed25519 + url = https://github.com/nervosnetwork/ed25519.git diff --git a/Makefile b/Makefile index 1c46576..dd37997 100644 --- a/Makefile +++ b/Makefile @@ -1,67 +1,72 @@ + TARGET := riscv64-unknown-linux-gnu CC := $(TARGET)-gcc LD := $(TARGET)-gcc OBJCOPY := $(TARGET)-objcopy -CFLAGS := -fPIC -O3 -fno-builtin-printf -fno-builtin-memcmp -nostdinc -nostdlib -nostartfiles -fvisibility=hidden -fdata-sections -ffunction-sections -I deps/secp256k1/src -I deps/secp256k1 -I deps/ckb-c-std-lib -I deps/ckb-c-std-lib/libc -I deps/ckb-c-std-lib/molecule -I c -I build -Wall -Werror -Wno-nonnull -Wno-nonnull-compare -Wno-unused-function -g -LDFLAGS := -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -SECP256K1_SRC_20210801 := deps/secp256k1-20210801/src/ecmult_static_pre_context.h +CFLAGS := -g -fPIC -O3 -fno-builtin \ + -nostdinc -nostdlib -nostartfiles -fvisibility=hidden -fdata-sections -ffunction-sections \ + -I deps/secp256k1/src -I deps/secp256k1 -I deps/ckb-c-stdlib -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib/molecule -I c -I build -I deps/sparse-merkle-tree/c \ + -Wall -Werror -Wno-nonnull -Wno-nonnull-compare -Wno-unused-function -Wno-array-bounds -Wno-stringop-overflow + +# to enable log +# -DCKB_C_STDLIB_PRINTF -DCKB_C_STDLIB_PRINTF_BUFFER_SIZE=1024 +LDFLAGS := -nostdlib -nostartfiles -Wl,-static -Wl,--gc-sections -OMNI_LOCK_CFLAGS :=$(subst ckb-c-std-lib,ckb-c-stdlib-20210801,$(CFLAGS)) -I deps/sparse-merkle-tree/c -OMNI_LOCK_CFLAGS := $(subst secp256k1,secp256k1-20210801,$(OMNI_LOCK_CFLAGS)) +SECP256K1_SRC := deps/secp256k1/src/ecmult_static_pre_context.h -PROTOCOL_HEADER := c/blockchain.h -PROTOCOL_SCHEMA := c/blockchain.mol -PROTOCOL_VERSION := d75e4c56ffa40e17fd2fe477da3f98c5578edcd1 -PROTOCOL_URL := https://raw.githubusercontent.com/nervosnetwork/ckb/${PROTOCOL_VERSION}/util/types/schemas/blockchain.mol MOLC := moleculec MOLC_VERSION := 0.7.0 -# docker pull nervos/ckb-riscv-gnu-toolchain:gnu-bionic-20191012 -BUILDER_DOCKER := nervos/ckb-riscv-gnu-toolchain@sha256:aae8a3f79705f67d505d1f1d5ddc694a4fd537ed1c7e9622420a470d59ba2ec3 -CLANG_FORMAT_DOCKER := kason223/clang-format@sha256:3cce35b0400a7d420ec8504558a02bdfc12fd2d10e40206f140c4545059cd95d +# docker pull nervos/ckb-riscv-gnu-toolchain:gnu-jammy-20230214 +BUILDER_DOCKER := nervos/ckb-riscv-gnu-toolchain@sha256:d3f649ef8079395eb25a21ceaeb15674f47eaa2d8cc23adc8bcdae3d5abce6ec +CLANG_FORMAT_DOCKER := xujiandong/ckb-riscv-llvm-toolchain@sha256:6409ab0d3e335c74088b54f4f73252f4b3367ae364d5c7ca7acee82135f5af4d all: build/omni_lock build/always_success -all-via-docker: ${PROTOCOL_HEADER} - docker run --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make" - +all-via-docker: + docker run -u $(shell id -u):$(shell id -g) --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make" build/always_success: c/always_success.c - $(CC) $(OMNI_LOCK_CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(OBJCOPY) --only-keep-debug $@ $@.debug $(OBJCOPY) --strip-debug --strip-all $@ -build/secp256k1_data_info_20210801.h: build/dump_secp256k1_data_20210801 +build/secp256k1_data_info.h: build/dump_secp256k1_data $< -build/dump_secp256k1_data_20210801: c/dump_secp256k1_data_20210801.c $(SECP256K1_SRC_20210801) +build/dump_secp256k1_data: c/dump_secp256k1_data.c $(SECP256K1_SRC) mkdir -p build - gcc -I deps/secp256k1-20210801/src -I deps/secp256k1-20210801 -o $@ $< + gcc -I deps/secp256k1/src -I deps/secp256k1 -I deps/ckb-c-stdlib -o $@ $< -$(SECP256K1_SRC_20210801): - cd deps/secp256k1-20210801 && \ +$(SECP256K1_SRC): + cd deps/secp256k1 && \ ./autogen.sh && \ - CC=$(CC) LD=$(LD) ./configure --with-bignum=no --enable-ecmult-static-precomputation --enable-endomorphism --enable-module-recovery --host=$(TARGET) && \ + CC=$(CC) LD=$(LD) ./configure --enable-ecmult-static-precomputation --with-ecmult-window=6 --enable-module-recovery --host=$(TARGET) && \ make src/ecmult_static_pre_context.h src/ecmult_static_context.h +build/ed25519/%.o: deps/ed25519/src/%.c + mkdir -p build/ed25519 + $(CC) -c -DCKB_DECLARATION_ONLY -I deps/ed25519/src $(CFLAGS) -o $@ $^ -build/impl.o: deps/ckb-c-std-lib/libc/src/impl.c - $(CC) -c $(filter-out -DCKB_DECLARATION_ONLY, $(CFLAGS_MBEDTLS)) $(LDFLAGS_MBEDTLS) -o $@ $^ +build/libed25519.a: build/ed25519/sign.o build/ed25519/verify.o build/ed25519/sha512.o build/ed25519/sc.o build/ed25519/keypair.o \ + build/ed25519/key_exchange.o build/ed25519/ge.o build/ed25519/fe.o build/ed25519/add_scalar.o + $(AR) cr $@ $^ -${PROTOCOL_SCHEMA}: - curl -L -o $@ ${PROTOCOL_URL} ALL_C_SOURCE := $(wildcard c/omni_lock.c c/omni_lock_acp.h c/omni_lock_time_lock.h \ - tests/omni_lock/omni_lock_sim.c tests/omni_lock/ckb_syscall_omni_lock_sim.h tests/omni_lock/omni_lock_supply.h) + tests/omni_lock/omni_lock_sim.c tests/omni_lock/ckb_syscall_omni_lock_sim.h tests/omni_lock/omni_lock_supply.h\ + c/cobuild.h c/molecule2_verify.h mol2_utils.h) fmt: - docker run --rm -v `pwd`:/code ${CLANG_FORMAT_DOCKER} bash -c "cd code && clang-format -i -style=Google $(ALL_C_SOURCE)" + docker run -u $(shell id -u):$(shell id -g) --rm -v `pwd`:/code ${CLANG_FORMAT_DOCKER} bash -c "cd code && clang-format -i -style='{BasedOnStyle: google, SortIncludes: false}' $(ALL_C_SOURCE)" git diff --exit-code $(ALL_C_SOURCE) mol: make omni_lock_mol + make cobuild_mol c/xudt_rce_mol.h: c/xudt_rce.mol ${MOLC} --language c --schema-file $< > $@ @@ -76,25 +81,34 @@ omni_lock_mol: ${MOLC} --language - --schema-file c/omni_lock.mol --format json > build/omni_lock_mol2.json moleculec-c2 --input build/omni_lock_mol2.json | clang-format -style=Google > c/omni_lock_mol2.h -build/omni_lock: c/omni_lock.c c/omni_lock_supply.h c/omni_lock_acp.h c/secp256k1_lock.h build/secp256k1_data_info_20210801.h $(SECP256K1_SRC_20210801) c/ckb_identity.h - $(CC) $(OMNI_LOCK_CFLAGS) $(LDFLAGS) -o $@ $< +build/omni_lock: c/omni_lock.c c/omni_lock_supply.h c/omni_lock_acp.h build/secp256k1_data_info.h $(SECP256K1_SRC) \ + c/ckb_identity.h c/mol2_utils.h c/cobuild_basic_mol2.h c/molecule2_verify.h \ + c/cobuild.h c/mol2_utils.h c/molecule2_verify.h build/libed25519.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< build/libed25519.a cp $@ $@.debug $(OBJCOPY) --strip-debug --strip-all $@ - -clean: - rm -rf build/secp256k1_data_info_20210801.h build/dump_secp256k1_data_20210801 - rm -rf build/secp256k1_data_20210801 +cobuild_mol: + ${MOLC} --language rust --schema-file c/basic.mol | rustfmt > tests/omni_lock_rust/src/schemas/basic.rs + ${MOLC} --language rust --schema-file c/top_level.mol | rustfmt > tests/omni_lock_rust/src/schemas/top_level.rs + ${MOLC} --language - --schema-file c/basic.mol --format json > build/cobuild_basic_mol2.json + moleculec-c2 --input build/cobuild_basic_mol2.json | clang-format -style=Google > c/cobuild_basic_mol2.h + ${MOLC} --language - --schema-file c/top_level.mol --format json > build/cobuild_top_level_mol2.json + moleculec-c2 --input build/cobuild_top_level_mol2.json | clang-format -style=Google > c/cobuild_top_level_mol2.h + +clean: clean2 + rm -rf build/secp256k1_data_info.h build/dump_secp256k1_data + rm -f build/secp256k1_data + rm -rf build/ed25519 build/libed25519.a + cd deps/secp256k1 && [ -f "Makefile" ] && make clean + +# not clean libraries, e.g. secp256k1 +clean2: rm -rf build/*.debug rm -f build/omni_lock - cd deps/secp256k1-20210801 && [ -f "Makefile" ] && make clean - -install-tools: - if [ ! -x "$$(command -v "${MOLC}")" ] \ - || [ "$$(${MOLC} --version | awk '{ print $$2 }' | tr -d ' ')" != "${MOLC_VERSION}" ]; then \ - cargo install --force --version "${MOLC_VERSION}" "${MOLC}"; \ - fi - + rm -f build/*.o + rm -f build/always_success + dist: clean all .PHONY: all all-via-docker dist clean package-clean package publish diff --git a/README.md b/README.md index 9c80f45..2bfae43 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,4 @@ cd tests/omni_lock_rust && cargo test ## Deployment See [RFC](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0042-omnilock/0042-omnilock.md) + diff --git a/c/basic.mol b/c/basic.mol new file mode 100644 index 0000000..21a2242 --- /dev/null +++ b/c/basic.mol @@ -0,0 +1,81 @@ +import blockchain; + +array Hash [byte; 32]; +vector String ; // UTF-8 encoded +option Uint32Opt (Uint32); + +table Action { + script_info_hash: Byte32, // script info + script_hash: Byte32, // script + data: Bytes, // action data +} + +vector ActionVec ; + +table Message { + actions: ActionVec, +} + +table ScriptInfo { + // The dapp name and domain the script belongs to + name: String, + url: String, + + // Script info. + // schema: script action schema + // message_type: the entry action type used in WitnessLayout + script_hash: Byte32, + schema: String, + message_type: String, +} + +vector ScriptInfoVec ; + +table ResolvedInputs { + outputs: CellOutputVec, + outputs_data: BytesVec, +} + +table BuildingPacketV1 { + message: Message, + payload: Transaction, + resolved_inputs: ResolvedInputs, + change_output: Uint32Opt, + script_infos: ScriptInfoVec, + lock_actions: ActionVec, +} + +union BuildingPacket { + BuildingPacketV1, +} + +table SighashAll { + message: Message, + seal: Bytes, +} + +table SighashAllOnly { + seal: Bytes, +} + +table SealPair { + script_hash: Byte32, + seal: Bytes, +} +vector SealPairVec ; + +table OtxStart { + start_input_cell: Uint32, + start_output_cell: Uint32, + start_cell_deps: Uint32, + start_header_deps: Uint32, +} + +table Otx { + input_cells: Uint32, + output_cells: Uint32, + cell_deps: Uint32, + header_deps: Uint32, + message: Message, + seals: SealPairVec, +} \ No newline at end of file diff --git a/c/blake2b.h b/c/blake2b.h deleted file mode 100644 index a0f5810..0000000 --- a/c/blake2b.h +++ /dev/null @@ -1,542 +0,0 @@ -/* - BLAKE2 reference source code package - reference C implementations - - Copyright 2012, Samuel Neves . You may use this under the - terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at - your option. The terms of these licenses can be found at: - - - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 - - OpenSSL license : https://www.openssl.org/source/license.html - - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 - - More information about the BLAKE2 hash function can be found at - https://blake2.net. -*/ - -// blake2.h -#ifndef BLAKE2_H -#define BLAKE2_H - -#include -#include - -#if defined(_MSC_VER) -#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) -#else -#define BLAKE2_PACKED(x) x __attribute__((packed)) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - - enum blake2b_constant - { - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 - }; - - typedef struct blake2b_state__ - { - uint64_t h[8]; - uint64_t t[2]; - uint64_t f[2]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - size_t buflen; - size_t outlen; - uint8_t last_node; - } blake2b_state; - - BLAKE2_PACKED(struct blake2b_param__ - { - uint8_t digest_length; /* 1 */ - uint8_t key_length; /* 2 */ - uint8_t fanout; /* 3 */ - uint8_t depth; /* 4 */ - uint32_t leaf_length; /* 8 */ - uint32_t node_offset; /* 12 */ - uint32_t xof_length; /* 16 */ - uint8_t node_depth; /* 17 */ - uint8_t inner_length; /* 18 */ - uint8_t reserved[14]; /* 32 */ - uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ - uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ - }); - - typedef struct blake2b_param__ blake2b_param; - - /* Padded structs result in a compile-time error */ - enum { - BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) - }; - - /* Streaming API */ - int blake2b_init( blake2b_state *S, size_t outlen ); - int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); - int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); - int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); - int blake2b_final( blake2b_state *S, void *out, size_t outlen ); - - /* Simple API */ - int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); - - /* This is simply an alias for blake2b */ - int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); - -#if defined(__cplusplus) -} -#endif - -#endif - -//blake2-impl.h -#ifndef BLAKE2_IMPL_H -#define BLAKE2_IMPL_H - -#include -#include - -#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) - #if defined(_MSC_VER) - #define BLAKE2_INLINE __inline - #elif defined(__GNUC__) - #define BLAKE2_INLINE __inline__ - #else - #define BLAKE2_INLINE - #endif -#else - #define BLAKE2_INLINE inline -#endif - -static BLAKE2_INLINE uint64_t load64( const void *src ) -{ -#if defined(NATIVE_LITTLE_ENDIAN) - uint64_t w; - memcpy(&w, src, sizeof w); - return w; -#else - const uint8_t *p = ( const uint8_t * )src; - return (( uint64_t )( p[0] ) << 0) | - (( uint64_t )( p[1] ) << 8) | - (( uint64_t )( p[2] ) << 16) | - (( uint64_t )( p[3] ) << 24) | - (( uint64_t )( p[4] ) << 32) | - (( uint64_t )( p[5] ) << 40) | - (( uint64_t )( p[6] ) << 48) | - (( uint64_t )( p[7] ) << 56) ; -#endif -} - -static BLAKE2_INLINE void store32( void *dst, uint32_t w ) -{ -#if defined(NATIVE_LITTLE_ENDIAN) - memcpy(dst, &w, sizeof w); -#else - uint8_t *p = ( uint8_t * )dst; - p[0] = (uint8_t)(w >> 0); - p[1] = (uint8_t)(w >> 8); - p[2] = (uint8_t)(w >> 16); - p[3] = (uint8_t)(w >> 24); -#endif -} - -static BLAKE2_INLINE void store64( void *dst, uint64_t w ) -{ -#if defined(NATIVE_LITTLE_ENDIAN) - memcpy(dst, &w, sizeof w); -#else - uint8_t *p = ( uint8_t * )dst; - p[0] = (uint8_t)(w >> 0); - p[1] = (uint8_t)(w >> 8); - p[2] = (uint8_t)(w >> 16); - p[3] = (uint8_t)(w >> 24); - p[4] = (uint8_t)(w >> 32); - p[5] = (uint8_t)(w >> 40); - p[6] = (uint8_t)(w >> 48); - p[7] = (uint8_t)(w >> 56); -#endif -} - -static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) -{ - return ( w >> c ) | ( w << ( 64 - c ) ); -} - -/* prevents compiler optimizing out memset() */ -static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) -{ - static void *(*const volatile memset_v)(void *, int, size_t) = &memset; - memset_v(v, 0, n); -} - -#endif - -// blake2b-ref.c -#include -#include -#include - -static const uint64_t blake2b_IV[8] = -{ - 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL -}; - -static const uint8_t blake2b_sigma[12][16] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } -}; - - -static void blake2b_set_lastnode( blake2b_state *S ) -{ - S->f[1] = (uint64_t)-1; -} - -/* Some helper functions, not necessarily useful */ -static int blake2b_is_lastblock( const blake2b_state *S ) -{ - return S->f[0] != 0; -} - -static void blake2b_set_lastblock( blake2b_state *S ) -{ - if( S->last_node ) blake2b_set_lastnode( S ); - - S->f[0] = (uint64_t)-1; -} - -static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) -{ - S->t[0] += inc; - S->t[1] += ( S->t[0] < inc ); -} - -static void blake2b_init0( blake2b_state *S ) -{ - size_t i; - memset( S, 0, sizeof( blake2b_state ) ); - - for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; -} - -/* init xors IV with input parameter block */ -int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) -{ - const uint8_t *p = ( const uint8_t * )( P ); - size_t i; - - blake2b_init0( S ); - - /* IV XOR ParamBlock */ - for( i = 0; i < 8; ++i ) - S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); - - S->outlen = P->digest_length; - return 0; -} - - -const char *DEFAULT_PERSONAL = "ckb-default-hash"; -int blake2b_init( blake2b_state *S, size_t outlen ) -{ - blake2b_param P[1]; - - if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store32( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - memset( P->reserved, 0, sizeof( P->reserved ) ); - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); - for (int i = 0; i < BLAKE2B_PERSONALBYTES; ++i) { - (P->personal)[i] = DEFAULT_PERSONAL[i]; - } - return blake2b_init_param( S, P ); -} - - -int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) -{ - blake2b_param P[1]; - - if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; - - if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = (uint8_t)keylen; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store32( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - memset( P->reserved, 0, sizeof( P->reserved ) ); - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); - - if( blake2b_init_param( S, P ) < 0 ) return -1; - - { - uint8_t block[BLAKE2B_BLOCKBYTES]; - memset( block, 0, BLAKE2B_BLOCKBYTES ); - memcpy( block, key, keylen ); - blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); - secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ - } - return 0; -} - -#define G(r,i,a,b,c,d) \ - do { \ - a = a + b + m[blake2b_sigma[r][2*i+0]]; \ - d = rotr64(d ^ a, 32); \ - c = c + d; \ - b = rotr64(b ^ c, 24); \ - a = a + b + m[blake2b_sigma[r][2*i+1]]; \ - d = rotr64(d ^ a, 16); \ - c = c + d; \ - b = rotr64(b ^ c, 63); \ - } while(0) - -#define ROUND(r) \ - do { \ - G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ - G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ - G(r,2,v[ 2],v[ 6],v[10],v[14]); \ - G(r,3,v[ 3],v[ 7],v[11],v[15]); \ - G(r,4,v[ 0],v[ 5],v[10],v[15]); \ - G(r,5,v[ 1],v[ 6],v[11],v[12]); \ - G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ - G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ - } while(0) - -static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) -{ - uint64_t m[16]; - uint64_t v[16]; - size_t i; - - for( i = 0; i < 16; ++i ) { - m[i] = load64( block + i * sizeof( m[i] ) ); - } - - for( i = 0; i < 8; ++i ) { - v[i] = S->h[i]; - } - - v[ 8] = blake2b_IV[0]; - v[ 9] = blake2b_IV[1]; - v[10] = blake2b_IV[2]; - v[11] = blake2b_IV[3]; - v[12] = blake2b_IV[4] ^ S->t[0]; - v[13] = blake2b_IV[5] ^ S->t[1]; - v[14] = blake2b_IV[6] ^ S->f[0]; - v[15] = blake2b_IV[7] ^ S->f[1]; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - ROUND( 10 ); - ROUND( 11 ); - - for( i = 0; i < 8; ++i ) { - S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; - } -} - -#undef G -#undef ROUND - -int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) -{ - const unsigned char * in = (const unsigned char *)pin; - if( inlen > 0 ) - { - size_t left = S->buflen; - size_t fill = BLAKE2B_BLOCKBYTES - left; - if( inlen > fill ) - { - S->buflen = 0; - memcpy( S->buf + left, in, fill ); /* Fill buffer */ - blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); - blake2b_compress( S, S->buf ); /* Compress */ - in += fill; inlen -= fill; - while(inlen > BLAKE2B_BLOCKBYTES) { - blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress( S, in ); - in += BLAKE2B_BLOCKBYTES; - inlen -= BLAKE2B_BLOCKBYTES; - } - } - memcpy( S->buf + S->buflen, in, inlen ); - S->buflen += inlen; - } - return 0; -} - -int blake2b_final( blake2b_state *S, void *out, size_t outlen ) -{ - uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; - size_t i; - - if( out == NULL || outlen < S->outlen ) - return -1; - - if( blake2b_is_lastblock( S ) ) - return -1; - - blake2b_increment_counter( S, S->buflen ); - blake2b_set_lastblock( S ); - memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ - blake2b_compress( S, S->buf ); - - for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ - store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); - - memcpy( out, buffer, S->outlen ); - secure_zero_memory(buffer, sizeof(buffer)); - return 0; -} - -/* inlen, at least, should be uint64_t. Others can be size_t. */ -int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) -{ - blake2b_state S[1]; - - /* Verify parameters */ - if ( NULL == in && inlen > 0 ) return -1; - - if ( NULL == out ) return -1; - - if( NULL == key && keylen > 0 ) return -1; - - if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; - - if( keylen > BLAKE2B_KEYBYTES ) return -1; - - if( keylen > 0 ) - { - if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; - } - else - { - if( blake2b_init( S, outlen ) < 0 ) return -1; - } - - blake2b_update( S, ( const uint8_t * )in, inlen ); - blake2b_final( S, out, outlen ); - return 0; -} - -int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { - return blake2b(out, outlen, in, inlen, key, keylen); -} - -#if defined(SUPERCOP) -int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) -{ - return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); -} -#endif - -#if defined(BLAKE2B_SELFTEST) -#include -#include "blake2-kat.h" -int main( void ) -{ - uint8_t key[BLAKE2B_KEYBYTES]; - uint8_t buf[BLAKE2_KAT_LENGTH]; - size_t i, step; - - for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) - key[i] = ( uint8_t )i; - - for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) - buf[i] = ( uint8_t )i; - - /* Test simple API */ - for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) - { - uint8_t hash[BLAKE2B_OUTBYTES]; - blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); - - if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) - { - goto fail; - } - } - - /* Test streaming API */ - for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { - for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { - uint8_t hash[BLAKE2B_OUTBYTES]; - blake2b_state S; - uint8_t * p = buf; - size_t mlen = i; - int err = 0; - - if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { - goto fail; - } - - while (mlen >= step) { - if ( (err = blake2b_update(&S, p, step)) < 0 ) { - goto fail; - } - mlen -= step; - p += step; - } - if ( (err = blake2b_update(&S, p, mlen)) < 0) { - goto fail; - } - if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { - goto fail; - } - - if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { - goto fail; - } - } - } - - puts( "ok" ); - return 0; -fail: - puts("error"); - return -1; -} -#endif - diff --git a/c/ckb_identity.h b/c/ckb_identity.h index dbdb1c1..daef488 100644 --- a/c/ckb_identity.h +++ b/c/ckb_identity.h @@ -1,8 +1,10 @@ #ifndef CKB_C_STDLIB_CKB_IDENTITY_H_ #define CKB_C_STDLIB_CKB_IDENTITY_H_ + #include #include +#include "blockchain.h" #include "ckb_consts.h" #include "ckb_keccak256.h" #include "ripemd160.h" @@ -24,14 +26,16 @@ #define SECP256K1_MESSAGE_SIZE 32 #define MAX_PREIMAGE_SIZE 1024 #define MESSAGE_HEX_LEN 64 +#define ED25519_SIGNATURE_SIZE 64 +#define ED25519_PUBKEY_SIZE 32 const char BTC_PREFIX[] = "CKB (Bitcoin Layer) transaction: 0x"; // BTC_PREFIX_LEN = 35 -const size_t BTC_PREFIX_LEN = sizeof(BTC_PREFIX) - 1; +#define BTC_PREFIX_LEN (sizeof(BTC_PREFIX) - 1) const char COMMON_PREFIX[] = "CKB transaction: 0x"; -// COMMON_PREFIX_LEN = 17 -const size_t COMMON_PREFIX_LEN = sizeof(COMMON_PREFIX) - 1; +// COMMON_PREFIX_LEN = 19 +#define COMMON_PREFIX_LEN (sizeof(COMMON_PREFIX) - 1) enum CkbIdentityErrorCode { ERROR_IDENTITY_ARGUMENTS_LEN = -1, @@ -61,7 +65,6 @@ typedef struct CkbIdentityType { enum IdentityFlagsType { IdentityFlagsCkb = 0, - // values 1~5 are used by pw-lock IdentityFlagsEthereum = 1, IdentityFlagsEos = 2, IdentityFlagsTron = 3, @@ -70,6 +73,7 @@ enum IdentityFlagsType { IdentityCkbMultisig = 6, IdentityFlagsEthereumDisplaying = 18, + IdentityFlagsSolana = 19, IdentityFlagsOwnerLock = 0xFC, IdentityFlagsExec = 0xFD, IdentityFlagsDl = 0xFE, @@ -163,8 +167,7 @@ static int _ckb_recover_secp256k1_pubkey(const uint8_t *sig, size_t sig_len, /* Load signature */ secp256k1_context context; - uint8_t secp_data[CKB_SECP256K1_DATA_SIZE]; - ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data); + ret = ckb_secp256k1_custom_verify_only_initialize(&context); if (ret != 0) { return ret; } @@ -285,8 +288,7 @@ static int _recover_secp256k1_pubkey_btc(const uint8_t *sig, size_t sig_len, } secp256k1_context context; - uint8_t secp_data[CKB_SECP256K1_DATA_SIZE]; - ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data); + ret = ckb_secp256k1_custom_verify_only_initialize(&context); if (ret != 0) { return ret; } @@ -374,6 +376,37 @@ int validate_signature_eos(void *prefilled_data, const uint8_t *sig, return err; } +int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key); +int validate_signature_solana(void *prefilled_data, const uint8_t *sig, + size_t sig_len, const uint8_t *msg, size_t msg_len, + uint8_t *output, size_t *output_len) { + if (*output_len < AUTH160_SIZE || msg_len != SHA256_SIZE) { + return ERROR_INVALID_ARG; + } + + // CKB transaction: 0x + uint8_t displaying_msg[COMMON_PREFIX_LEN + MESSAGE_HEX_LEN] = {0}; + memcpy(displaying_msg, COMMON_PREFIX, COMMON_PREFIX_LEN); + bin_to_hex(msg, displaying_msg + COMMON_PREFIX_LEN, msg_len); + + // Unlike secp256k1, Ed25519 cannot recover the public key from the signature alone. + // The public key is located immediately after the signature. + const uint8_t* pubkey = sig + ED25519_SIGNATURE_SIZE; + int success = ed25519_verify(sig, displaying_msg, sizeof(displaying_msg), pubkey); + if (!success) { + return ERROR_MISMATCHED; + } + + uint8_t hash[SHA256_SIZE] = {0}; + blake2b_state ctx; + blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE); + blake2b_update(&ctx, pubkey, ED25519_PUBKEY_SIZE); + blake2b_final(&ctx, hash, BLAKE2B_BLOCK_SIZE); + memcpy(output, hash, AUTH160_SIZE); + *output_len = AUTH160_SIZE; + return 0; +} + int generate_sighash_all(uint8_t *msg, size_t msg_len) { int ret; uint64_t len = 0; @@ -385,6 +418,7 @@ int generate_sighash_all(uint8_t *msg, size_t msg_len) { return ERROR_IDENTITY_ARGUMENTS_LEN; } + // TODO: migrate this to molecule-c2 so we don't need MAX_WITNESS_SIZE /* Load witness of first input */ ret = ckb_load_witness(temp, &read_len, 0, 0, CKB_SOURCE_GROUP_INPUT); if (ret != CKB_SUCCESS) { @@ -522,15 +556,10 @@ static int convert_eth_message_displaying(const uint8_t *msg, size_t msg_len, } int verify_sighash_all(uint8_t *pubkey_hash, uint8_t *sig, uint32_t sig_len, - validate_signature_t func, convert_msg_t convert) { + validate_signature_t func, convert_msg_t convert, const uint8_t* signing_message_hash) { int ret = 0; - uint8_t old_msg[BLAKE2B_BLOCK_SIZE]; uint8_t new_msg[BLAKE2B_BLOCK_SIZE]; - ret = generate_sighash_all(old_msg, sizeof(old_msg)); - if (ret != 0) { - return ret; - } - ret = convert(old_msg, sizeof(old_msg), new_msg, sizeof(new_msg)); + ret = convert(signing_message_hash, BLAKE2B_BLOCK_SIZE, new_msg, sizeof(new_msg)); if (ret != 0) return ret; uint8_t output_pubkey_hash[BLAKE160_SIZE]; @@ -671,7 +700,7 @@ bool is_lock_script_hash_present(uint8_t *lock_script_hash) { int verify_via_dl(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, uint8_t *preimage, uint32_t preimage_len, - CkbSwappableSignatureInstance *inst) { + CkbSwappableSignatureInstance *inst, const uint8_t* signing_message_hash) { int err = 0; uint8_t hash[BLAKE2B_BLOCK_SIZE]; @@ -694,11 +723,11 @@ int verify_via_dl(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, if (err != 0) return err; return verify_sighash_all(pubkey_hash, sig, sig_len, inst->verify_func, - _ckb_convert_copy); + _ckb_convert_copy, signing_message_hash); } int verify_via_exec(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, - uint8_t *preimage, uint32_t preimage_len) { + uint8_t *preimage, uint32_t preimage_len, const uint8_t* signing_message_hash) { int err = 0; uint8_t hash[BLAKE2B_BLOCK_SIZE]; @@ -710,9 +739,6 @@ int verify_via_exec(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, if (preimage_len != (32 + 1 + 1 + 8 + 20)) { return ERROR_INVALID_PREIMAGE; } - - int ret = 0; - // check preimage hash blake2b_state ctx; blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE); @@ -722,12 +748,6 @@ int verify_via_exec(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, return ERROR_INVALID_PREIMAGE; } - // get message - uint8_t msg[BLAKE2B_BLOCK_SIZE]; - ret = generate_sighash_all(msg, sizeof(msg)); - if (ret != 0) { - return ret; - } uint8_t *code_hash = preimage; uint8_t hash_type = *(preimage + 32); @@ -748,7 +768,7 @@ int verify_via_exec(CkbIdentityType *id, uint8_t *sig, uint32_t sig_len, if (err != 0) return err; err = ckb_exec_append(&bin_args, pubkey_hash, 20); if (err != 0) return err; - err = ckb_exec_append(&bin_args, msg, sizeof(msg)); + err = ckb_exec_append(&bin_args, (uint8_t*)signing_message_hash, BLAKE2B_BLOCK_SIZE); if (err != 0) return err; err = ckb_exec_append(&bin_args, sig, sig_len); if (err != 0) return err; @@ -837,8 +857,7 @@ int verify_multisig(const uint8_t *lock_bytes, size_t lock_bytes_len, // contract, you don't have to wait for the foundation to ship a new // cryptographic algorithm. You can just build and ship your own. secp256k1_context context; - uint8_t secp_data[CKB_SECP256K1_DATA_SIZE]; - ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data); + ret = ckb_secp256k1_custom_verify_only_initialize(&context); if (ret != 0) return ret; // We will perform *threshold* number of signature verifications here. @@ -912,54 +931,57 @@ static uint8_t *g_identity_code_buffer = NULL; static uint32_t g_identity_code_size = 0; int ckb_verify_identity(CkbIdentityType *id, uint8_t *sig, uint32_t sig_size, - uint8_t *preimage, uint32_t preimage_size) { + uint8_t *preimage, uint32_t preimage_size, const uint8_t* signing_message_hash) { if (id->flags == IdentityFlagsCkb) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, - validate_signature_secp256k1, _ckb_convert_copy); + validate_signature_secp256k1, _ckb_convert_copy, signing_message_hash); } else if (id->flags == IdentityFlagsEthereum) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, - convert_eth_message); + convert_eth_message, signing_message_hash); } else if (id->flags == IdentityFlagsEthereumDisplaying) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, - convert_eth_message_displaying); + convert_eth_message_displaying, signing_message_hash); } else if (id->flags == IdentityFlagsEos) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_eos, - convert_copy); + convert_copy, signing_message_hash); } else if (id->flags == IdentityFlagsTron) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_eth, - convert_tron_message); + convert_tron_message, signing_message_hash); } else if (id->flags == IdentityFlagsBitcoin) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_btc, - convert_btc_message); + convert_btc_message, signing_message_hash); } else if (id->flags == IdentityFlagsDogecoin) { if (sig == NULL || sig_size != SECP256K1_SIGNATURE_SIZE) { return ERROR_IDENTITY_WRONG_ARGS; } return verify_sighash_all(id->id, sig, sig_size, validate_signature_btc, - convert_doge_message); + convert_doge_message, signing_message_hash); + } else if (id->flags == IdentityFlagsSolana) { + if (sig == NULL || sig_size != (ED25519_SIGNATURE_SIZE + ED25519_PUBKEY_SIZE)) { + return ERROR_IDENTITY_WRONG_ARGS; + } + return verify_sighash_all(id->id, sig, sig_size, validate_signature_solana, + convert_copy, signing_message_hash); } else if (id->flags == IdentityCkbMultisig) { - uint8_t msg[BLAKE2B_BLOCK_SIZE]; - int ret = generate_sighash_all(msg, sizeof(msg)); - if (ret != 0) return ret; - return verify_multisig(sig, sig_size, msg, id->id); + return verify_multisig(sig, sig_size, signing_message_hash, id->id); } else if (id->flags == IdentityFlagsOwnerLock) { if (is_lock_script_hash_present(id->id)) { return 0; @@ -975,9 +997,9 @@ int ckb_verify_identity(CkbIdentityType *id, uint8_t *sig, uint32_t sig_size, .prefilled_buffer_size = 0, .verify_func = NULL}; return verify_via_dl(id, sig, sig_size, preimage, preimage_size, - &swappable_inst); + &swappable_inst, signing_message_hash); } else if (id->flags == IdentityFlagsExec) { - return verify_via_exec(id, sig, sig_size, preimage, preimage_size); + return verify_via_exec(id, sig, sig_size, preimage, preimage_size, signing_message_hash); } return CKB_INVALID_DATA; } diff --git a/c/cobuild.h b/c/cobuild.h new file mode 100644 index 0000000..afe29c5 --- /dev/null +++ b/c/cobuild.h @@ -0,0 +1,916 @@ +/** CKB Transaction Cobuild Helper Library + * The `ckb_cobuild_entry` function serves as the primary entry point for + * cobuild integration. + * + * To begin, a callback function for signature validation should be implemented: + * + * int lock_entry(const Env *env, const uint8_t *smh, mol2_cursor_t seal) { + * // Validate smh (signing message hash) against seal (signature) + * // Any legacy script code can be moved here + * } + * + * Afterward, the `ckb_cobuild_entry` function is invoked: + * + * ckb_env_initialize(&env); + * + * bool cobuild_activated = false; + * err = ckb_cobuild_entry(&env, omnilock_entry, &cobuild_activated); + * if (err) { + * // Implement error handling code here + * ckb_exit(err); + * } + * printf("cobuild_activated = %d", cobuild_activated); + * if (!cobuild_activated) { + * // Any legacy script code can be placed here + * // This may include reading witness, script arguments, validating + * // signatures, etc. + * } + */ +#ifndef __COBUILD_H__ +#define __COBUILD_H__ + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +#include "molecule2_reader.h" +#include "mol2_utils.h" +#include "molecule2_reader.h" +#include "blockchain-api2.h" +#include "cobuild_basic_mol2.h" +#include "cobuild_top_level_mol2.h" +#include "molecule2_verify.h" + +#include "blake2b.h" +#include "ckb_consts.h" +#include "ckb_syscall_apis.h" +// clang-format on +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define BLAKE2B_BLOCK_SIZE 32 +#define MAX_SCRIPT_COUNT 512 + +#define CKB_COBUILD_CHECK2(cond, code) \ + do { \ + if (!(cond)) { \ + printf("error at %s:%d, error code %d", __FILE__, __LINE__, code); \ + err = code; \ + ASSERT(0); \ + goto exit; \ + } \ + } while (0) + +#define CKB_COBUILD_CHECK(_code) \ + do { \ + int code = (_code); \ + if (code != 0) { \ + printf("error at %s:%d, error code %d", __FILE__, __LINE__, code); \ + err = code; \ + ASSERT(0); \ + goto exit; \ + } \ + } while (0) + +#define CKB_COBUILD_CHECK_LOOP(err) \ + if (err == CKB_INDEX_OUT_OF_BOUND) { \ + err = 0; \ + break; \ + } \ + CKB_COBUILD_CHECK(err) + +enum CobuildErrorCode { + // cobuild error code is from 110 + COBUILD_ERROR_GENERAL = 110, + COBUILD_ERROR_HASH, + COBUILD_ERROR_NONEMPTY_WITNESS, + COBUILD_ERROR_SIGHASHALL_DUP, + COBUILD_ERROR_SIGHASHALL_NOSEAL, + COBUILD_ERROR_MESSAGE, + COBUILD_ERROR_TYPESCRIPT_MISSING, + COBUILD_ERROR_SEAL, + COBUILD_ERROR_FLOW, + COBUILD_ERROR_OTX_START_DUP, + COBUILD_ERROR_WRONG_OTX, + COBUILD_ERROR_NOT_COBUILD, + COBUILD_ERROR_NO_CALLBACK, + COBUILD_ERROR_MOL2_UNEXPECTED, + COBUILD_ERROR_OVERFLOW, +}; + +typedef int (*ScriptEntryType)(const Env *env, + const uint8_t *signing_message_hash, + mol2_cursor_t seal); + +enum MessageCalculationFlow { + MessageCalculationFlowBlake2b = 0, +}; + +typedef struct OtxStart { + uint32_t start_input_cell; + uint32_t start_output_cell; + uint32_t start_cell_deps; + uint32_t start_header_deps; +} OtxStart; + +typedef struct Otx { + uint32_t input_cells; + uint32_t output_cells; + uint32_t cell_deps; + uint32_t header_deps; +} Otx; + +const char *PERSONAL_SIGHASH_ALL = "ckb-tcob-sighash"; +const char *PERSONAL_SIGHASH_ALL_ONLY = "ckb-tcob-sgohash"; +const char *PERSONAL_OTX = "ckb-tcob-otxhash"; + +#ifdef CKB_C_STDLIB_PRINTF +void print_raw_data(const char *name, uint8_t *data, size_t len) { + uint8_t str[924] = {0}; + const int limit = (sizeof(str) - 1) / 2; + if (len > limit) { + printf("The data length (%d) is too long, truncated to %d", len, limit); + len = limit; + } + bin_to_hex(data, str, len); + printf("%s(len=%d): %s", name, len, str); +} + +void print_cursor(const char *name, mol2_cursor_t cursor) { + uint8_t data[256] = {0}; + uint32_t read_len = mol2_read_at(&cursor, data, sizeof(data)); + if (read_len >= sizeof(data)) { + printf("the cursor length (%d) is too long, truncated to %d", cursor.size, + read_len); + } + print_raw_data(name, data, MIN(read_len, sizeof(data))); +} + +// After being enabled, there will be a lot of logs. +// #define BLAKE2B_UPDATE blake2b_update_debug +#define BLAKE2B_UPDATE blake2b_update +int blake2b_update_debug(blake2b_state *S, const void *pin, size_t inlen) { + blake2b_update(S, pin, inlen); + print_raw_data("blake2b_update", (uint8_t *)pin, inlen); + return 0; +} + +#else + +void print_raw_data(const char *name, const uint8_t *data, size_t len) {} +void print_cursor(const char *name, mol2_cursor_t cursor) {} +#define BLAKE2B_UPDATE blake2b_update + +#endif + +int ckb_blake2b_init_personal(blake2b_state *S, size_t outlen, + const char *personal) { + blake2b_param P[1]; + + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store32(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); + for (int i = 0; i < BLAKE2B_PERSONALBYTES; ++i) { + (P->personal)[i] = personal[i]; + } + return blake2b_init_param(S, P); +} + +int new_sighash_all_blake2b(blake2b_state *S) { + return ckb_blake2b_init_personal(S, 32, PERSONAL_SIGHASH_ALL); +} + +int new_sighash_all_only_blake2b(blake2b_state *S) { + return ckb_blake2b_init_personal(S, 32, PERSONAL_SIGHASH_ALL_ONLY); +} + +int new_otx_blake2b(blake2b_state *S) { + return ckb_blake2b_init_personal(S, 32, PERSONAL_OTX); +} + +static inline int get_witness_layout(BytesVecType witnesses, uint32_t index, + WitnessLayoutType *witness_layout, + bool verify_recursively) { + bool existing = false; + mol2_cursor_t witness = witnesses.t->get(&witnesses, index, &existing); + if (!existing) { + return COBUILD_ERROR_MOL2_UNEXPECTED; + } + + WitnessLayoutType witness_layout2 = make_WitnessLayout(&witness); + if (verify_WitnessLayout(&witness_layout2, verify_recursively)) { + return COBUILD_ERROR_GENERAL; + } + if (witness_layout != NULL) { + *witness_layout = witness_layout2; + } + return 0; +} + +// for lock script with message, the other witness in script group except first +// one should be empty +int ckb_check_others_in_group() { + int err = COBUILD_ERROR_GENERAL; + for (size_t index = 1;; index++) { + uint64_t witness_len = 0; + err = ckb_load_witness(0, &witness_len, 0, index, CKB_SOURCE_GROUP_INPUT); + CKB_COBUILD_CHECK_LOOP(err); + // tested by test_non_empty_witness + CKB_COBUILD_CHECK2(witness_len == 0, COBUILD_ERROR_NONEMPTY_WITNESS); + } + +exit: + return err; +} + +int ckb_fetch_sighash_message(BytesVecType witnesses, MessageType *message) { + int err = 0; + bool has_message = false; + uint32_t witness_len = witnesses.t->len(&witnesses); + for (uint32_t index = 0; index < witness_len; index++) { + WitnessLayoutType witness_layout = {0}; + if (get_witness_layout(witnesses, index, &witness_layout, false) == 0) { + uint32_t id = witness_layout.t->item_id(&witness_layout); + if (id == WitnessLayoutSighashAll) { + // tested by: + // tested_by_sighashall_dup + CKB_COBUILD_CHECK2(!has_message, COBUILD_ERROR_SIGHASHALL_DUP); + SighashAllType s = witness_layout.t->as_SighashAll(&witness_layout); + *message = s.t->message(&s); + has_message = true; + } + } + // there are some possibilities: + // 1. an invalid witness (e.g. empty) + // 2. WitnessArgs + // 3. Other cobuild WitnessLayout(e.g. SighashAllOnly) + // tested by: + // tested_by_append_witnessed_less_than_4 + // tested_by_append_witnessargs + // tested_by_append_other_witnesslayout + } +exit: + return err; +} + +// step 2 +static inline int ckb_fetch_otx_start(BytesVecType witnesses, bool *has_otx, + size_t *i, OtxStart *otx_start) { + int err = COBUILD_ERROR_GENERAL; + *has_otx = false; + uint32_t witness_len = witnesses.t->len(&witnesses); + for (uint32_t index = 0; index < witness_len; index++) { + WitnessLayoutType witness_layout = {0}; + err = get_witness_layout(witnesses, index, &witness_layout, false); + if (err == 0) { + uint32_t id = witness_layout.t->item_id(&witness_layout); + if (id == WitnessLayoutOtxStart) { + // step 4 + // test_cobuild_otx_double_otx_start + CKB_COBUILD_CHECK2(!*has_otx, COBUILD_ERROR_OTX_START_DUP); + *has_otx = true; + *i = index; + + OtxStartType start = witness_layout.t->as_OtxStart(&witness_layout); + otx_start->start_input_cell = start.t->start_input_cell(&start); + otx_start->start_output_cell = start.t->start_output_cell(&start); + otx_start->start_cell_deps = start.t->start_cell_deps(&start); + otx_start->start_header_deps = start.t->start_header_deps(&start); + } + } + } + if (has_otx) { + err = 0; + } +exit: + return err; +} +// hash input cell, including CellOutput and cell data +static int hash_input_cell(blake2b_state *ctx, size_t index, size_t *count) { + // this data source is on stack. When this function returns, all cursors bound + // to this buffer become invalid. + uint8_t data_source[DEFAULT_DATA_SOURCE_LENGTH]; + int err = 0; + // CellOutput + uint64_t cell_len = MAX_CACHE_SIZE; + err = ckb_load_cell(MOL2_CACHE_PTR(data_source), &cell_len, 0, index, + CKB_SOURCE_INPUT); + CKB_COBUILD_CHECK(err); + mol2_cursor_t cell_cursor = {0}; + uint32_t cache_size = (uint32_t)cell_len; + if (cache_size > MAX_CACHE_SIZE) { + cache_size = MAX_CACHE_SIZE; + } + ckb_new_cursor_with_data(&cell_cursor, cell_len, read_from_cell, data_source, + MAX_CACHE_SIZE, index, CKB_SOURCE_INPUT, cache_size); + ckb_hash_cursor(ctx, cell_cursor); + (*count) += cell_len; + + // Cell data + uint64_t cell_data_len = MAX_CACHE_SIZE; + err = ckb_load_cell_data(MOL2_CACHE_PTR(data_source), &cell_data_len, 0, + index, CKB_SOURCE_INPUT); + CKB_COBUILD_CHECK(err); + mol2_cursor_t cell_data_cursor = {0}; + cache_size = (uint32_t)cell_data_len; + if (cache_size > MAX_CACHE_SIZE) { + cache_size = MAX_CACHE_SIZE; + } + ckb_new_cursor_with_data(&cell_data_cursor, cell_data_len, + read_from_cell_data, data_source, MAX_CACHE_SIZE, + index, CKB_SOURCE_INPUT, cache_size); + // only hash as uint32_t. 4 bytes is enough + BLAKE2B_UPDATE(ctx, &cell_data_len, 4); + (*count) += 4; + err = ckb_hash_cursor(ctx, cell_data_cursor); + CKB_COBUILD_CHECK(err); + (*count) += cell_data_cursor.size; + +exit: + return err; +} + +int ckb_generate_smh(const Env *env, mol2_cursor_t message_cursor, + uint8_t *smh) { + bool has_message = message_cursor.size > 0; + int err = 0; + + blake2b_state ctx; + size_t count = 0; + // use different hash based on message + if (has_message) { + // tested by test_input_cell_data_size_0 + new_sighash_all_blake2b(&ctx); + ckb_hash_cursor(&ctx, message_cursor); + count += message_cursor.size; + } else { + // tested by: + // tested_by_no_has_message + new_sighash_all_only_blake2b(&ctx); + } + + // hash tx hash + BLAKE2B_UPDATE(&ctx, env->tx_hash, sizeof(env->tx_hash)); + count += sizeof(env->tx_hash); + + TransactionType tx = env->tx; + RawTransactionType raw = tx.t->raw(&tx); + CellInputVecType inputs = raw.t->inputs(&raw); + uint32_t input_len = inputs.t->len(&inputs); + BytesVecType witnesses = tx.t->witnesses(&tx); + uint32_t witness_len = witnesses.t->len(&witnesses); + + // hash input cell and data + for (uint32_t index = 0; index < input_len; index++) { + err = hash_input_cell(&ctx, index, &count); + CKB_COBUILD_CHECK(err); + } + // hash remaining witnesses + for (uint32_t index = input_len; index < witness_len; index++) { + bool existing = false; + mol2_cursor_t witness_cursor = + witnesses.t->get(&witnesses, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + uint32_t witness_len = witness_cursor.size; + BLAKE2B_UPDATE(&ctx, &witness_len, 4); + count += 4; + err = ckb_hash_cursor(&ctx, witness_cursor); + count += witness_cursor.size; + CKB_COBUILD_CHECK(err); + } + blake2b_final(&ctx, smh, BLAKE2B_BLOCK_SIZE); + printf("ckb_generate_smh total hashed %zu bytes", count); + +exit: + return err; +} + +static int hash_cmp(const void *h1, const void *h2) { + return memcmp(h1, h2, BLAKE2B_BLOCK_SIZE); +} + +static int collect_script_hash(uint8_t *script_hash, + uint32_t *script_hash_count, size_t source, + size_t field) { + int err = 0; + size_t i = 0; + while (1) { + uint8_t hash[BLAKE2B_BLOCK_SIZE] = {0}; + uint64_t len = BLAKE2B_BLOCK_SIZE; + err = ckb_load_cell_by_field(hash, &len, 0, i, source, field); + if (err == CKB_INDEX_OUT_OF_BOUND) { + err = 0; + break; + } + if (err == CKB_ITEM_MISSING) { + i += 1; + continue; + } + CKB_COBUILD_CHECK(err); + CKB_COBUILD_CHECK2(*script_hash_count < MAX_SCRIPT_COUNT, + COBUILD_ERROR_GENERAL); + memcpy(&script_hash[(*script_hash_count) * BLAKE2B_BLOCK_SIZE], hash, + BLAKE2B_BLOCK_SIZE); + (*script_hash_count)++; + i += 1; + } +exit: + return err; +} + +// For each action in the message, ensure a corresponding type script hash +// (including input/output) matches the action.script_hash. Let A be the set of +// action.script_hash, and B be the set of all input/output script hashes; A ∈ B +// should be satisfied. +static int check_type_script_existing(MessageType msg) { + int err = 0; + // cache all type script hashes in input/output cells + static uint8_t script_hash[BLAKE2B_BLOCK_SIZE * MAX_SCRIPT_COUNT] = {0}; + static uint32_t script_hash_count = 0; + static bool script_hash_initialized = false; + + if (!script_hash_initialized) { + err = collect_script_hash(script_hash, &script_hash_count, CKB_SOURCE_INPUT, + CKB_CELL_FIELD_TYPE_HASH); + CKB_COBUILD_CHECK(err); + err = collect_script_hash(script_hash, &script_hash_count, + CKB_SOURCE_OUTPUT, CKB_CELL_FIELD_TYPE_HASH); + CKB_COBUILD_CHECK(err); + err = collect_script_hash(script_hash, &script_hash_count, CKB_SOURCE_INPUT, + CKB_CELL_FIELD_LOCK_HASH); + CKB_COBUILD_CHECK(err); + + // sort for fast searching + qsort(script_hash, script_hash_count, BLAKE2B_BLOCK_SIZE, hash_cmp); + + script_hash_initialized = true; + } + + ActionVecType actions = msg.t->actions(&msg); + uint32_t len = actions.t->len(&actions); + for (uint32_t i = 0; i < len; i++) { + bool existing = false; + ActionType action = actions.t->get(&actions, i, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_GENERAL); + mol2_cursor_t hash = action.t->script_hash(&action); + uint8_t hash_buff[BLAKE2B_BLOCK_SIZE] = {0}; + uint32_t len = mol2_read_at(&hash, hash_buff, BLAKE2B_BLOCK_SIZE); + CKB_COBUILD_CHECK2(len == BLAKE2B_BLOCK_SIZE, COBUILD_ERROR_MESSAGE); + void *found = bsearch(hash_buff, script_hash, script_hash_count, + BLAKE2B_BLOCK_SIZE, hash_cmp); + // test_cobuild_otx_noexistent_type_script_hash + CKB_COBUILD_CHECK2(found != NULL, COBUILD_ERROR_TYPESCRIPT_MISSING); + } + +exit: + return err; +} + +// Parse the `original_seal` and return underlying seal after adjustment. The +// first byte of `seal` is considered as an id of message calculation flow. +static int parse_seal(const mol2_cursor_t original_seal, mol2_cursor_t *seal, + uint8_t *message_calculation_flow) { + int err = 0; + // message calculation flow is not part of cobuild protocol. + // Some of lock scripts may need this. +#ifdef DISABLE_MESSAGE_CALCULATION_FLOW + *seal = original_seal; + *message_calculation_flow = 0; + return 0; +#endif + + uint32_t prefix_length = 1; + uint8_t prefix[1] = {0}; + + uint32_t len = mol2_read_at(&original_seal, prefix, prefix_length); + CKB_COBUILD_CHECK2(len == prefix_length, COBUILD_ERROR_SEAL); + *message_calculation_flow = prefix[0]; + *seal = mol2_cursor_slice_start(&original_seal, prefix_length); + +exit: + return err; +} + +int ckb_cobuild_normal_entry(const Env *env, ScriptEntryType callback) { + TransactionType tx = env->tx; + BytesVecType witnesses = tx.t->witnesses(&tx); + + int err = COBUILD_ERROR_GENERAL; + uint8_t smh[BLAKE2B_BLOCK_SIZE]; + mol2_cursor_t seal = {0}; + + MessageType message = {0}; + // step 8.a, 8.b + err = ckb_fetch_sighash_message(witnesses, &message); + CKB_COBUILD_CHECK(err); + bool has_message = message.cur.size > 0; + if (has_message) { + print_cursor("message", message.cur); + // step 8.c + err = check_type_script_existing(message); + CKB_COBUILD_CHECK(err); + } + + uint8_t seal_source[DEFAULT_DATA_SOURCE_LENGTH]; + mol2_cursor_t original_seal = {0}; + { + // step 8.d + // step 8.f + mol2_cursor_t witness = {0}; + err = ckb_new_witness_cursor(&witness, seal_source, MAX_CACHE_SIZE, 0, + CKB_SOURCE_GROUP_INPUT); + CKB_COBUILD_CHECK(err); + WitnessLayoutType witness_layout = make_WitnessLayout(&witness); + CKB_COBUILD_CHECK2(!verify_WitnessLayout(&witness_layout, false), + COBUILD_ERROR_SIGHASHALL_NOSEAL); + + uint32_t id = witness_layout.t->item_id(&witness_layout); + switch (id) { + case WitnessLayoutSighashAll: { + SighashAllType s = witness_layout.t->as_SighashAll(&witness_layout); + original_seal = s.t->seal(&s); + } break; + case WitnessLayoutSighashAllOnly: { + SighashAllOnlyType o = + witness_layout.t->as_SighashAllOnly(&witness_layout); + original_seal = o.t->seal(&o); + } break; + default: { + // the union id should be SighashAll or SighashAllOnly. otherwise, it + // fails and mark it as non cobuild. tested by test_wrong_union_id + printf("error in fetch_seal, id = %u", id); + CKB_COBUILD_CHECK2(false, COBUILD_ERROR_SIGHASHALL_NOSEAL); + } break; + } + } + print_cursor("seal", original_seal); + + // step 8.e + err = ckb_check_others_in_group(); + // tested by test_non_empty_witness + CKB_COBUILD_CHECK(err); + + // support more message calculation flows base on the first byte of seal + uint8_t message_calculation_flow = 0; + err = parse_seal(original_seal, &seal, &message_calculation_flow); + CKB_COBUILD_CHECK(err); + + if (message_calculation_flow == MessageCalculationFlowBlake2b) { + // step 8.g + err = ckb_generate_smh(env, message.cur, smh); + CKB_COBUILD_CHECK(err); + print_raw_data("smh", smh, BLAKE2B_BLOCK_SIZE); + } else { + // we can add more message calculation flows in the further, based on the + // first byte of seal + CKB_COBUILD_CHECK2(false, COBUILD_ERROR_FLOW); + } + err = callback(env, smh, seal); + if (err) { + printf("callback failed: %d", err); + // terminated immediately + ckb_exit(err); + } +exit: + return err; +} + +int ckb_generate_otx_smh(const Env *env, mol2_cursor_t message_cursor, + uint8_t *smh, const OtxStart *start, const Otx *size) { + int err = 0; + blake2b_state ctx; + size_t count = 0; + new_otx_blake2b(&ctx); + printf( + "start_input_cell = %d, start_output_cell = %d, start_cell_deps = %d, " + "start_header_deps = %d", + start->start_input_cell, start->start_output_cell, start->start_cell_deps, + start->start_header_deps); + printf( + "input_cells = %d, output_cells = %d, cell_deps = %d, header_deps = %d", + size->input_cells, size->output_cells, size->cell_deps, + size->header_deps); + + err = ckb_hash_cursor(&ctx, message_cursor); + CKB_COBUILD_CHECK(err); + count += message_cursor.size; + + BLAKE2B_UPDATE(&ctx, &size->input_cells, 4); + count += 4; + + TransactionType tx = env->tx; + RawTransactionType raw = tx.t->raw(&tx); + CellInputVecType inputs = raw.t->inputs(&raw); + + // hash input cell and data + CKB_COBUILD_CHECK2( + start->start_input_cell + size->input_cells >= start->start_input_cell, + COBUILD_ERROR_OVERFLOW); + for (size_t index = start->start_input_cell; + index < (start->start_input_cell + size->input_cells); index++) { + // CellInput + bool existing = false; + CellInputType input = inputs.t->get(&inputs, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + err = ckb_hash_cursor(&ctx, input.cur); + CKB_COBUILD_CHECK(err); + count += input.cur.size; + + err = hash_input_cell(&ctx, index, &count); + CKB_COBUILD_CHECK(err); + } + // hash output cell and data + CKB_COBUILD_CHECK2( + start->start_output_cell + size->output_cells >= start->start_output_cell, + COBUILD_ERROR_OVERFLOW); + BLAKE2B_UPDATE(&ctx, &size->output_cells, 4); + count += 4; + CellOutputVecType outputs = raw.t->outputs(&raw); + BytesVecType outputs_data = raw.t->outputs_data(&raw); + for (size_t index = start->start_output_cell; + index < (start->start_output_cell + size->output_cells); index++) { + bool existing = false; + CellOutputType output = outputs.t->get(&outputs, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + err = ckb_hash_cursor(&ctx, output.cur); + CKB_COBUILD_CHECK(err); + count += output.cur.size; + + existing = false; + mol2_cursor_t output_data_cursor = + outputs_data.t->get(&outputs_data, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + uint32_t data_len = output_data_cursor.size; + BLAKE2B_UPDATE(&ctx, &data_len, 4); + count += 4; + err = ckb_hash_cursor(&ctx, output_data_cursor); + CKB_COBUILD_CHECK(err); + count += output_data_cursor.size; + } + + // hash cell deps + CKB_COBUILD_CHECK2( + start->start_cell_deps + size->cell_deps >= start->start_cell_deps, + COBUILD_ERROR_OVERFLOW); + BLAKE2B_UPDATE(&ctx, &size->cell_deps, 4); + count += 4; + CellDepVecType cell_deps = raw.t->cell_deps(&raw); + for (size_t index = start->start_cell_deps; + index < (start->start_cell_deps + size->cell_deps); index++) { + bool existing = false; + CellDepType cell_dep = cell_deps.t->get(&cell_deps, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + err = ckb_hash_cursor(&ctx, cell_dep.cur); + count += cell_dep.cur.size; + } + + // hash header deps + CKB_COBUILD_CHECK2( + start->start_header_deps + size->header_deps >= start->start_header_deps, + COBUILD_ERROR_OVERFLOW); + BLAKE2B_UPDATE(&ctx, &size->header_deps, 4); + count += 4; + Byte32VecType header_deps = raw.t->header_deps(&raw); + for (size_t index = start->start_header_deps; + index < (start->start_header_deps + size->header_deps); index++) { + bool existing = false; + mol2_cursor_t header_dep_cursor = + header_deps.t->get(&header_deps, index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_MOL2_UNEXPECTED); + err = ckb_hash_cursor(&ctx, header_dep_cursor); + count += header_dep_cursor.size; + } + printf("ckb_generate_otx_smh totally hashed %zu bytes", count); + blake2b_final(&ctx, smh, BLAKE2B_BLOCK_SIZE); +exit: + return err; +} + +int ckb_cobuild_entry(const Env *env, ScriptEntryType callback, + bool *cobuild_enabled) { + int err = 0; + size_t execution_count = 0; + uint8_t smh[BLAKE2B_BLOCK_SIZE] = {0}; + mol2_cursor_t original_seal = {0}; + mol2_cursor_t seal = {0}; + + TransactionType tx = env->tx; + BytesVecType witnesses = tx.t->witnesses(&tx); + uint32_t witness_len = witnesses.t->len(&witnesses); + + // Legacy Flow Handling + *cobuild_enabled = false; + for (uint32_t i = 0; i < witness_len; i++) { + if (get_witness_layout(witnesses, i, NULL, true) == 0) { + *cobuild_enabled = true; + // Do not break here. All witnesses are recursively verified at this + // point. Subsequent witnesses will not be recursively verified. + } + } + if (!*cobuild_enabled) { + goto exit; + } + + // step 1 + uint32_t is = 0, ie = 0, os = 0, oe = 0, cs = 0, ce = 0, hs = 0, he = 0; + size_t i = 0; + bool has_otx = false; + OtxStart otx_start = {0}; + // step 2 + // step 4 + err = ckb_fetch_otx_start(witnesses, &has_otx, &i, &otx_start); + CKB_COBUILD_CHECK(err); + if (!has_otx) { + // step 3 + printf("No otx detected"); + return ckb_cobuild_normal_entry(env, callback); + } + // step 5 + is = otx_start.start_input_cell; + ie = is; + os = otx_start.start_output_cell; + oe = os; + cs = otx_start.start_cell_deps; + ce = cs; + hs = otx_start.start_header_deps; + he = hs; + printf("ie = %d, oe = %d, ce = %d, he = %d", ie, oe, ce, he); + uint32_t index = i + 1; + printf("Otx starts at index %d(inclusive)", index); + for (; index < witness_len; index++) { + WitnessLayoutType witness_layout = {0}; + err = get_witness_layout(witnesses, index, &witness_layout, false); + if (err != 0) { + // step 6, not WitnessLayoutOtx + break; + } + uint32_t id = witness_layout.t->item_id(&witness_layout); + if (id != WitnessLayoutOtx) { + // step 6 + // test_cobuild_otx_noexistent_otx_id && err == 0 + break; + } + OtxType otx = witness_layout.t->as_Otx(&witness_layout); + MessageType message = otx.t->message(&otx); + Otx size = { + .input_cells = otx.t->input_cells(&otx), + .output_cells = otx.t->output_cells(&otx), + .cell_deps = otx.t->cell_deps(&otx), + .header_deps = otx.t->header_deps(&otx), + }; + // 6.b + if (size.input_cells == 0 && size.output_cells == 0 && + size.cell_deps == 0 && size.header_deps == 0) { + // test_cobuild_otx_msg_size_all_0 + CKB_COBUILD_CHECK2(false, COBUILD_ERROR_WRONG_OTX); + } + // step 6.c + err = check_type_script_existing(message); + CKB_COBUILD_CHECK(err); + // step 6.d + bool found = false; + size_t end = (size_t)(ie + otx.t->input_cells(&otx)); + for (size_t index2 = ie; index2 < end; index2++) { + uint8_t hash[BLAKE2B_BLOCK_SIZE]; + uint64_t len = BLAKE2B_BLOCK_SIZE; + err = ckb_load_cell_by_field(hash, &len, 0, index2, CKB_SOURCE_INPUT, + CKB_CELL_FIELD_LOCK_HASH); + CKB_COBUILD_CHECK(err); + if (memcmp(hash, env->current_script_hash, sizeof(hash)) == 0) { + found = true; + break; + } + } + if (!found) { + ie += otx.t->input_cells(&otx); + oe += otx.t->output_cells(&otx); + ce += otx.t->cell_deps(&otx); + he += otx.t->header_deps(&otx); + continue; + } + // step 6.e + OtxStart start = { + .start_input_cell = ie, + .start_output_cell = oe, + .start_cell_deps = ce, + .start_header_deps = he, + }; + err = ckb_generate_otx_smh(env, message.cur, smh, &start, &size); + CKB_COBUILD_CHECK(err); + print_raw_data("smh", smh, BLAKE2B_BLOCK_SIZE); + // step 6.f + bool seal_found = false; + SealPairVecType seals = otx.t->seals(&otx); + uint32_t seal_len = seals.t->len(&seals); + for (uint32_t seal_index = 0; seal_index < seal_len; seal_index++) { + bool existing = false; + uint8_t hash[BLAKE2B_BLOCK_SIZE]; + SealPairType loop_seal = seals.t->get(&seals, seal_index, &existing); + CKB_COBUILD_CHECK2(existing, COBUILD_ERROR_GENERAL); + mol2_cursor_t script_hash = loop_seal.t->script_hash(&loop_seal); + size_t len = mol2_read_at(&script_hash, hash, sizeof(hash)); + CKB_COBUILD_CHECK2(len == sizeof(hash), COBUILD_ERROR_GENERAL); + if (memcmp(hash, env->current_script_hash, sizeof(hash)) == 0) { + // step 6.g + original_seal = loop_seal.t->seal(&loop_seal); + print_cursor("seal", original_seal); + // duplicated seals are ignored + seal_found = true; + break; + } + } + // test_cobuild_otx_no_seal + CKB_COBUILD_CHECK2(seal_found, COBUILD_ERROR_SEAL); + // support more message calculation flows base on the first byte of seal + uint8_t message_calculation_flow = 0; + err = parse_seal(original_seal, &seal, &message_calculation_flow); + CKB_COBUILD_CHECK(err); + if (message_calculation_flow == MessageCalculationFlowBlake2b) { + execution_count++; + err = callback(env, smh, seal); + if (err) { + printf("callback failed: %d", err); + // terminated immediately + ckb_exit(err); + } + } else { + // test_cobuild_otx_msg_flow + CKB_COBUILD_CHECK2(false, COBUILD_ERROR_FLOW); + } + // step 6.h + ie += otx.t->input_cells(&otx); + oe += otx.t->output_cells(&otx); + ce += otx.t->cell_deps(&otx); + he += otx.t->header_deps(&otx); + } // end of step 6 loop + printf("Otx ends at index %d(exclusive)", index); + + // step 7 + size_t j = index; + for (uint32_t index = 0; index < witness_len; index++) { + // [0, i) [j, +infinity) + if (index < i || index >= j) { + WitnessLayoutType witness_layout = {0}; + err = get_witness_layout(witnesses, index, &witness_layout, false); + if (err == 0) { + // test_cobuild_otx_noexistent_otx_id + uint32_t id = witness_layout.t->item_id(&witness_layout); + CKB_COBUILD_CHECK2(id != WitnessLayoutOtx, COBUILD_ERROR_WRONG_OTX); + } + } + } + + // step 8 + bool found = false; + for (size_t index = 0;; index++) { + // scan all input cell in [0, is) and [ie, +infinity) + // if is == ie, it is always true + if (index < is || index >= ie) { + uint8_t hash[BLAKE2B_BLOCK_SIZE]; + uint64_t len = BLAKE2B_BLOCK_SIZE; + err = ckb_load_cell_by_field(hash, &len, 0, index, CKB_SOURCE_INPUT, + CKB_CELL_FIELD_LOCK_HASH); + CKB_COBUILD_CHECK_LOOP(err); + if (memcmp(hash, env->current_script_hash, sizeof(hash)) == 0) { + printf( + "Same lock script found beyond otx, at index %zu. " + "ckb_cobuild_normal_entry called.", + index); + found = true; + break; + } + } + } + if (found) { + printf("extra callback is invoked"); + execution_count++; + err = ckb_cobuild_normal_entry(env, callback); + CKB_COBUILD_CHECK(err); + } + CKB_COBUILD_CHECK2(execution_count > 0, COBUILD_ERROR_NO_CALLBACK); + printf("execution_count = %zu", execution_count); +exit: + return err; +} + +#endif // __COBUILD_H__ diff --git a/c/cobuild_basic_mol2.h b/c/cobuild_basic_mol2.h new file mode 100644 index 0000000..71fd2fd --- /dev/null +++ b/c/cobuild_basic_mol2.h @@ -0,0 +1,883 @@ + +#ifndef _COBUILD_BASIC_MOL2_API2_H_ +#define _COBUILD_BASIC_MOL2_API2_H_ + +#ifndef MOLECULEC2_VERSION +#define MOLECULEC2_VERSION 7002 +#endif +#ifndef MOLECULE2_API_VERSION_MIN +#define MOLECULE2_API_VERSION_MIN 5000 +#endif + +#include "molecule2_reader.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +// ----forward declaration-------- +struct HashType; +struct HashVTable; +struct HashVTable *GetHashVTable(void); +struct HashType make_Hash(mol2_cursor_t *cur); +uint32_t Hash_len_impl(struct HashType *); +uint8_t Hash_get_impl(struct HashType *, uint32_t, bool *); +struct StringType; +struct StringVTable; +struct StringVTable *GetStringVTable(void); +struct StringType make_String(mol2_cursor_t *cur); +uint32_t String_len_impl(struct StringType *); +uint8_t String_get_impl(struct StringType *, uint32_t, bool *); +struct Uint32OptType; +struct Uint32OptVTable; +struct Uint32OptVTable *GetUint32OptVTable(void); +struct Uint32OptType make_Uint32Opt(mol2_cursor_t *cur); +bool Uint32Opt_is_none_impl(struct Uint32OptType *); +bool Uint32Opt_is_some_impl(struct Uint32OptType *); +uint32_t Uint32Opt_unwrap_impl(struct Uint32OptType *); +struct ActionType; +struct ActionVTable; +struct ActionVTable *GetActionVTable(void); +struct ActionType make_Action(mol2_cursor_t *cur); +mol2_cursor_t Action_get_script_info_hash_impl(struct ActionType *); +mol2_cursor_t Action_get_script_hash_impl(struct ActionType *); +mol2_cursor_t Action_get_data_impl(struct ActionType *); +struct ActionVecType; +struct ActionVecVTable; +struct ActionVecVTable *GetActionVecVTable(void); +struct ActionVecType make_ActionVec(mol2_cursor_t *cur); +uint32_t ActionVec_len_impl(struct ActionVecType *); +struct ActionType ActionVec_get_impl(struct ActionVecType *, uint32_t, bool *); +struct MessageType; +struct MessageVTable; +struct MessageVTable *GetMessageVTable(void); +struct MessageType make_Message(mol2_cursor_t *cur); +struct ActionVecType Message_get_actions_impl(struct MessageType *); +struct ScriptInfoType; +struct ScriptInfoVTable; +struct ScriptInfoVTable *GetScriptInfoVTable(void); +struct ScriptInfoType make_ScriptInfo(mol2_cursor_t *cur); +mol2_cursor_t ScriptInfo_get_name_impl(struct ScriptInfoType *); +mol2_cursor_t ScriptInfo_get_url_impl(struct ScriptInfoType *); +mol2_cursor_t ScriptInfo_get_script_hash_impl(struct ScriptInfoType *); +mol2_cursor_t ScriptInfo_get_schema_impl(struct ScriptInfoType *); +mol2_cursor_t ScriptInfo_get_message_type_impl(struct ScriptInfoType *); +struct ScriptInfoVecType; +struct ScriptInfoVecVTable; +struct ScriptInfoVecVTable *GetScriptInfoVecVTable(void); +struct ScriptInfoVecType make_ScriptInfoVec(mol2_cursor_t *cur); +uint32_t ScriptInfoVec_len_impl(struct ScriptInfoVecType *); +struct ScriptInfoType ScriptInfoVec_get_impl(struct ScriptInfoVecType *, + uint32_t, bool *); +struct ResolvedInputsType; +struct ResolvedInputsVTable; +struct ResolvedInputsVTable *GetResolvedInputsVTable(void); +struct ResolvedInputsType make_ResolvedInputs(mol2_cursor_t *cur); +struct CellOutputVecType ResolvedInputs_get_outputs_impl( + struct ResolvedInputsType *); +struct BytesVecType ResolvedInputs_get_outputs_data_impl( + struct ResolvedInputsType *); +struct BuildingPacketV1Type; +struct BuildingPacketV1VTable; +struct BuildingPacketV1VTable *GetBuildingPacketV1VTable(void); +struct BuildingPacketV1Type make_BuildingPacketV1(mol2_cursor_t *cur); +struct MessageType BuildingPacketV1_get_message_impl( + struct BuildingPacketV1Type *); +struct TransactionType BuildingPacketV1_get_payload_impl( + struct BuildingPacketV1Type *); +struct ResolvedInputsType BuildingPacketV1_get_resolved_inputs_impl( + struct BuildingPacketV1Type *); +struct Uint32OptType BuildingPacketV1_get_change_output_impl( + struct BuildingPacketV1Type *); +struct ScriptInfoVecType BuildingPacketV1_get_script_infos_impl( + struct BuildingPacketV1Type *); +struct ActionVecType BuildingPacketV1_get_lock_actions_impl( + struct BuildingPacketV1Type *); +struct BuildingPacketType; +struct BuildingPacketVTable; +struct BuildingPacketVTable *GetBuildingPacketVTable(void); +struct BuildingPacketType make_BuildingPacket(mol2_cursor_t *cur); +uint32_t BuildingPacket_item_id_impl(struct BuildingPacketType *); +struct BuildingPacketV1Type BuildingPacket_as_BuildingPacketV1_impl( + struct BuildingPacketType *); +struct SighashAllType; +struct SighashAllVTable; +struct SighashAllVTable *GetSighashAllVTable(void); +struct SighashAllType make_SighashAll(mol2_cursor_t *cur); +struct MessageType SighashAll_get_message_impl(struct SighashAllType *); +mol2_cursor_t SighashAll_get_seal_impl(struct SighashAllType *); +struct SighashAllOnlyType; +struct SighashAllOnlyVTable; +struct SighashAllOnlyVTable *GetSighashAllOnlyVTable(void); +struct SighashAllOnlyType make_SighashAllOnly(mol2_cursor_t *cur); +mol2_cursor_t SighashAllOnly_get_seal_impl(struct SighashAllOnlyType *); +struct SealPairType; +struct SealPairVTable; +struct SealPairVTable *GetSealPairVTable(void); +struct SealPairType make_SealPair(mol2_cursor_t *cur); +mol2_cursor_t SealPair_get_script_hash_impl(struct SealPairType *); +mol2_cursor_t SealPair_get_seal_impl(struct SealPairType *); +struct SealPairVecType; +struct SealPairVecVTable; +struct SealPairVecVTable *GetSealPairVecVTable(void); +struct SealPairVecType make_SealPairVec(mol2_cursor_t *cur); +uint32_t SealPairVec_len_impl(struct SealPairVecType *); +struct SealPairType SealPairVec_get_impl(struct SealPairVecType *, uint32_t, + bool *); +struct OtxStartType; +struct OtxStartVTable; +struct OtxStartVTable *GetOtxStartVTable(void); +struct OtxStartType make_OtxStart(mol2_cursor_t *cur); +uint32_t OtxStart_get_start_input_cell_impl(struct OtxStartType *); +uint32_t OtxStart_get_start_output_cell_impl(struct OtxStartType *); +uint32_t OtxStart_get_start_cell_deps_impl(struct OtxStartType *); +uint32_t OtxStart_get_start_header_deps_impl(struct OtxStartType *); +struct OtxType; +struct OtxVTable; +struct OtxVTable *GetOtxVTable(void); +struct OtxType make_Otx(mol2_cursor_t *cur); +uint32_t Otx_get_input_cells_impl(struct OtxType *); +uint32_t Otx_get_output_cells_impl(struct OtxType *); +uint32_t Otx_get_cell_deps_impl(struct OtxType *); +uint32_t Otx_get_header_deps_impl(struct OtxType *); +struct MessageType Otx_get_message_impl(struct OtxType *); +struct SealPairVecType Otx_get_seals_impl(struct OtxType *); + +// ----definition----------------- +typedef struct HashVTable { + uint32_t (*len)(struct HashType *); + uint8_t (*get)(struct HashType *, uint32_t, bool *); +} HashVTable; +typedef struct HashType { + mol2_cursor_t cur; + HashVTable *t; +} HashType; + +typedef struct StringVTable { + uint32_t (*len)(struct StringType *); + uint8_t (*get)(struct StringType *, uint32_t, bool *); +} StringVTable; +typedef struct StringType { + mol2_cursor_t cur; + StringVTable *t; +} StringType; + +typedef struct Uint32OptVTable { + bool (*is_none)(struct Uint32OptType *); + bool (*is_some)(struct Uint32OptType *); + uint32_t (*unwrap)(struct Uint32OptType *); +} Uint32OptVTable; +typedef struct Uint32OptType { + mol2_cursor_t cur; + Uint32OptVTable *t; +} Uint32OptType; + +typedef struct ActionVTable { + mol2_cursor_t (*script_info_hash)(struct ActionType *); + mol2_cursor_t (*script_hash)(struct ActionType *); + mol2_cursor_t (*data)(struct ActionType *); +} ActionVTable; +typedef struct ActionType { + mol2_cursor_t cur; + ActionVTable *t; +} ActionType; + +typedef struct ActionVecVTable { + uint32_t (*len)(struct ActionVecType *); + struct ActionType (*get)(struct ActionVecType *, uint32_t, bool *); +} ActionVecVTable; +typedef struct ActionVecType { + mol2_cursor_t cur; + ActionVecVTable *t; +} ActionVecType; + +typedef struct MessageVTable { + struct ActionVecType (*actions)(struct MessageType *); +} MessageVTable; +typedef struct MessageType { + mol2_cursor_t cur; + MessageVTable *t; +} MessageType; + +typedef struct ScriptInfoVTable { + mol2_cursor_t (*name)(struct ScriptInfoType *); + mol2_cursor_t (*url)(struct ScriptInfoType *); + mol2_cursor_t (*script_hash)(struct ScriptInfoType *); + mol2_cursor_t (*schema)(struct ScriptInfoType *); + mol2_cursor_t (*message_type)(struct ScriptInfoType *); +} ScriptInfoVTable; +typedef struct ScriptInfoType { + mol2_cursor_t cur; + ScriptInfoVTable *t; +} ScriptInfoType; + +typedef struct ScriptInfoVecVTable { + uint32_t (*len)(struct ScriptInfoVecType *); + struct ScriptInfoType (*get)(struct ScriptInfoVecType *, uint32_t, bool *); +} ScriptInfoVecVTable; +typedef struct ScriptInfoVecType { + mol2_cursor_t cur; + ScriptInfoVecVTable *t; +} ScriptInfoVecType; + +typedef struct ResolvedInputsVTable { + struct CellOutputVecType (*outputs)(struct ResolvedInputsType *); + struct BytesVecType (*outputs_data)(struct ResolvedInputsType *); +} ResolvedInputsVTable; +typedef struct ResolvedInputsType { + mol2_cursor_t cur; + ResolvedInputsVTable *t; +} ResolvedInputsType; + +typedef struct BuildingPacketV1VTable { + struct MessageType (*message)(struct BuildingPacketV1Type *); + struct TransactionType (*payload)(struct BuildingPacketV1Type *); + struct ResolvedInputsType (*resolved_inputs)(struct BuildingPacketV1Type *); + struct Uint32OptType (*change_output)(struct BuildingPacketV1Type *); + struct ScriptInfoVecType (*script_infos)(struct BuildingPacketV1Type *); + struct ActionVecType (*lock_actions)(struct BuildingPacketV1Type *); +} BuildingPacketV1VTable; +typedef struct BuildingPacketV1Type { + mol2_cursor_t cur; + BuildingPacketV1VTable *t; +} BuildingPacketV1Type; + +typedef struct BuildingPacketVTable { + uint32_t (*item_id)(struct BuildingPacketType *); + struct BuildingPacketV1Type (*as_BuildingPacketV1)( + struct BuildingPacketType *); +} BuildingPacketVTable; +typedef struct BuildingPacketType { + mol2_cursor_t cur; + BuildingPacketVTable *t; +} BuildingPacketType; + +typedef struct SighashAllVTable { + struct MessageType (*message)(struct SighashAllType *); + mol2_cursor_t (*seal)(struct SighashAllType *); +} SighashAllVTable; +typedef struct SighashAllType { + mol2_cursor_t cur; + SighashAllVTable *t; +} SighashAllType; + +typedef struct SighashAllOnlyVTable { + mol2_cursor_t (*seal)(struct SighashAllOnlyType *); +} SighashAllOnlyVTable; +typedef struct SighashAllOnlyType { + mol2_cursor_t cur; + SighashAllOnlyVTable *t; +} SighashAllOnlyType; + +typedef struct SealPairVTable { + mol2_cursor_t (*script_hash)(struct SealPairType *); + mol2_cursor_t (*seal)(struct SealPairType *); +} SealPairVTable; +typedef struct SealPairType { + mol2_cursor_t cur; + SealPairVTable *t; +} SealPairType; + +typedef struct SealPairVecVTable { + uint32_t (*len)(struct SealPairVecType *); + struct SealPairType (*get)(struct SealPairVecType *, uint32_t, bool *); +} SealPairVecVTable; +typedef struct SealPairVecType { + mol2_cursor_t cur; + SealPairVecVTable *t; +} SealPairVecType; + +typedef struct OtxStartVTable { + uint32_t (*start_input_cell)(struct OtxStartType *); + uint32_t (*start_output_cell)(struct OtxStartType *); + uint32_t (*start_cell_deps)(struct OtxStartType *); + uint32_t (*start_header_deps)(struct OtxStartType *); +} OtxStartVTable; +typedef struct OtxStartType { + mol2_cursor_t cur; + OtxStartVTable *t; +} OtxStartType; + +typedef struct OtxVTable { + uint32_t (*input_cells)(struct OtxType *); + uint32_t (*output_cells)(struct OtxType *); + uint32_t (*cell_deps)(struct OtxType *); + uint32_t (*header_deps)(struct OtxType *); + struct MessageType (*message)(struct OtxType *); + struct SealPairVecType (*seals)(struct OtxType *); +} OtxVTable; +typedef struct OtxType { + mol2_cursor_t cur; + OtxVTable *t; +} OtxType; + +#ifndef MOLECULEC_C2_DECLARATION_ONLY + +// ----implementation------------- +struct HashType make_Hash(mol2_cursor_t *cur) { + HashType ret; + ret.cur = *cur; + ret.t = GetHashVTable(); + return ret; +} +struct HashVTable *GetHashVTable(void) { + static HashVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.len = Hash_len_impl; + s_vtable.get = Hash_get_impl; + return &s_vtable; +} +uint32_t Hash_len_impl(HashType *this) { return 32; } +uint8_t Hash_get_impl(HashType *this, uint32_t index, bool *existing) { + uint8_t ret = {0}; + mol2_cursor_res_t res = mol2_slice_by_offset2(&this->cur, 1 * index, 1); + if (res.errno != MOL2_OK) { + *existing = false; + return ret; + } else { + *existing = true; + } + ret = convert_to_Uint8(&res.cur); + return ret; +} +struct StringType make_String(mol2_cursor_t *cur) { + StringType ret; + ret.cur = *cur; + ret.t = GetStringVTable(); + return ret; +} +struct StringVTable *GetStringVTable(void) { + static StringVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.len = String_len_impl; + s_vtable.get = String_get_impl; + return &s_vtable; +} +uint32_t String_len_impl(StringType *this) { + return mol2_fixvec_length(&this->cur); +} +uint8_t String_get_impl(StringType *this, uint32_t index, bool *existing) { + uint8_t ret = {0}; + mol2_cursor_res_t res = mol2_fixvec_slice_by_index(&this->cur, 1, index); + if (res.errno != MOL2_OK) { + *existing = false; + return ret; + } else { + *existing = true; + } + ret = convert_to_Uint8(&res.cur); + return ret; +} +struct Uint32OptType make_Uint32Opt(mol2_cursor_t *cur) { + Uint32OptType ret; + ret.cur = *cur; + ret.t = GetUint32OptVTable(); + return ret; +} +struct Uint32OptVTable *GetUint32OptVTable(void) { + static Uint32OptVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.is_none = Uint32Opt_is_none_impl; + s_vtable.is_some = Uint32Opt_is_some_impl; + s_vtable.unwrap = Uint32Opt_unwrap_impl; + return &s_vtable; +} +bool Uint32Opt_is_none_impl(Uint32OptType *this) { + return mol2_option_is_none(&this->cur); +} +bool Uint32Opt_is_some_impl(Uint32OptType *this) { + return !mol2_option_is_none(&this->cur); +} +uint32_t Uint32Opt_unwrap_impl(Uint32OptType *this) { + uint32_t ret; + ret = convert_to_Uint32(&this->cur); + return ret; +} +struct ActionType make_Action(mol2_cursor_t *cur) { + ActionType ret; + ret.cur = *cur; + ret.t = GetActionVTable(); + return ret; +} +struct ActionVTable *GetActionVTable(void) { + static ActionVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.script_info_hash = Action_get_script_info_hash_impl; + s_vtable.script_hash = Action_get_script_hash_impl; + s_vtable.data = Action_get_data_impl; + return &s_vtable; +} +mol2_cursor_t Action_get_script_info_hash_impl(ActionType *this) { + mol2_cursor_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_array(&ret2); + return ret; +} +mol2_cursor_t Action_get_script_hash_impl(ActionType *this) { + mol2_cursor_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_array(&ret2); + return ret; +} +mol2_cursor_t Action_get_data_impl(ActionType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 2); + ret = convert_to_rawbytes(&re2); + return ret; +} +struct ActionVecType make_ActionVec(mol2_cursor_t *cur) { + ActionVecType ret; + ret.cur = *cur; + ret.t = GetActionVecVTable(); + return ret; +} +struct ActionVecVTable *GetActionVecVTable(void) { + static ActionVecVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.len = ActionVec_len_impl; + s_vtable.get = ActionVec_get_impl; + return &s_vtable; +} +uint32_t ActionVec_len_impl(ActionVecType *this) { + return mol2_dynvec_length(&this->cur); +} +ActionType ActionVec_get_impl(ActionVecType *this, uint32_t index, + bool *existing) { + ActionType ret = {0}; + mol2_cursor_res_t res = mol2_dynvec_slice_by_index(&this->cur, index); + if (res.errno != MOL2_OK) { + *existing = false; + return ret; + } else { + *existing = true; + } + ret.cur = res.cur; + ret.t = GetActionVTable(); + return ret; +} +struct MessageType make_Message(mol2_cursor_t *cur) { + MessageType ret; + ret.cur = *cur; + ret.t = GetMessageVTable(); + return ret; +} +struct MessageVTable *GetMessageVTable(void) { + static MessageVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.actions = Message_get_actions_impl; + return &s_vtable; +} +ActionVecType Message_get_actions_impl(MessageType *this) { + ActionVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 0); + ret.cur = cur; + ret.t = GetActionVecVTable(); + return ret; +} +struct ScriptInfoType make_ScriptInfo(mol2_cursor_t *cur) { + ScriptInfoType ret; + ret.cur = *cur; + ret.t = GetScriptInfoVTable(); + return ret; +} +struct ScriptInfoVTable *GetScriptInfoVTable(void) { + static ScriptInfoVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.name = ScriptInfo_get_name_impl; + s_vtable.url = ScriptInfo_get_url_impl; + s_vtable.script_hash = ScriptInfo_get_script_hash_impl; + s_vtable.schema = ScriptInfo_get_schema_impl; + s_vtable.message_type = ScriptInfo_get_message_type_impl; + return &s_vtable; +} +mol2_cursor_t ScriptInfo_get_name_impl(ScriptInfoType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_rawbytes(&re2); + return ret; +} +mol2_cursor_t ScriptInfo_get_url_impl(ScriptInfoType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_rawbytes(&re2); + return ret; +} +mol2_cursor_t ScriptInfo_get_script_hash_impl(ScriptInfoType *this) { + mol2_cursor_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 2); + ret = convert_to_array(&ret2); + return ret; +} +mol2_cursor_t ScriptInfo_get_schema_impl(ScriptInfoType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 3); + ret = convert_to_rawbytes(&re2); + return ret; +} +mol2_cursor_t ScriptInfo_get_message_type_impl(ScriptInfoType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 4); + ret = convert_to_rawbytes(&re2); + return ret; +} +struct ScriptInfoVecType make_ScriptInfoVec(mol2_cursor_t *cur) { + ScriptInfoVecType ret; + ret.cur = *cur; + ret.t = GetScriptInfoVecVTable(); + return ret; +} +struct ScriptInfoVecVTable *GetScriptInfoVecVTable(void) { + static ScriptInfoVecVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.len = ScriptInfoVec_len_impl; + s_vtable.get = ScriptInfoVec_get_impl; + return &s_vtable; +} +uint32_t ScriptInfoVec_len_impl(ScriptInfoVecType *this) { + return mol2_dynvec_length(&this->cur); +} +ScriptInfoType ScriptInfoVec_get_impl(ScriptInfoVecType *this, uint32_t index, + bool *existing) { + ScriptInfoType ret = {0}; + mol2_cursor_res_t res = mol2_dynvec_slice_by_index(&this->cur, index); + if (res.errno != MOL2_OK) { + *existing = false; + return ret; + } else { + *existing = true; + } + ret.cur = res.cur; + ret.t = GetScriptInfoVTable(); + return ret; +} +struct ResolvedInputsType make_ResolvedInputs(mol2_cursor_t *cur) { + ResolvedInputsType ret; + ret.cur = *cur; + ret.t = GetResolvedInputsVTable(); + return ret; +} +struct ResolvedInputsVTable *GetResolvedInputsVTable(void) { + static ResolvedInputsVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.outputs = ResolvedInputs_get_outputs_impl; + s_vtable.outputs_data = ResolvedInputs_get_outputs_data_impl; + return &s_vtable; +} +CellOutputVecType ResolvedInputs_get_outputs_impl(ResolvedInputsType *this) { + CellOutputVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 0); + ret.cur = cur; + ret.t = GetCellOutputVecVTable(); + return ret; +} +BytesVecType ResolvedInputs_get_outputs_data_impl(ResolvedInputsType *this) { + BytesVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 1); + ret.cur = cur; + ret.t = GetBytesVecVTable(); + return ret; +} +struct BuildingPacketV1Type make_BuildingPacketV1(mol2_cursor_t *cur) { + BuildingPacketV1Type ret; + ret.cur = *cur; + ret.t = GetBuildingPacketV1VTable(); + return ret; +} +struct BuildingPacketV1VTable *GetBuildingPacketV1VTable(void) { + static BuildingPacketV1VTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.message = BuildingPacketV1_get_message_impl; + s_vtable.payload = BuildingPacketV1_get_payload_impl; + s_vtable.resolved_inputs = BuildingPacketV1_get_resolved_inputs_impl; + s_vtable.change_output = BuildingPacketV1_get_change_output_impl; + s_vtable.script_infos = BuildingPacketV1_get_script_infos_impl; + s_vtable.lock_actions = BuildingPacketV1_get_lock_actions_impl; + return &s_vtable; +} +MessageType BuildingPacketV1_get_message_impl(BuildingPacketV1Type *this) { + MessageType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 0); + ret.cur = cur; + ret.t = GetMessageVTable(); + return ret; +} +TransactionType BuildingPacketV1_get_payload_impl(BuildingPacketV1Type *this) { + TransactionType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 1); + ret.cur = cur; + ret.t = GetTransactionVTable(); + return ret; +} +ResolvedInputsType BuildingPacketV1_get_resolved_inputs_impl( + BuildingPacketV1Type *this) { + ResolvedInputsType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 2); + ret.cur = cur; + ret.t = GetResolvedInputsVTable(); + return ret; +} +Uint32OptType BuildingPacketV1_get_change_output_impl( + BuildingPacketV1Type *this) { + Uint32OptType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 3); + ret.cur = cur; + ret.t = GetUint32OptVTable(); + return ret; +} +ScriptInfoVecType BuildingPacketV1_get_script_infos_impl( + BuildingPacketV1Type *this) { + ScriptInfoVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 4); + ret.cur = cur; + ret.t = GetScriptInfoVecVTable(); + return ret; +} +ActionVecType BuildingPacketV1_get_lock_actions_impl( + BuildingPacketV1Type *this) { + ActionVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 5); + ret.cur = cur; + ret.t = GetActionVecVTable(); + return ret; +} +struct BuildingPacketType make_BuildingPacket(mol2_cursor_t *cur) { + BuildingPacketType ret; + ret.cur = *cur; + ret.t = GetBuildingPacketVTable(); + return ret; +} +struct BuildingPacketVTable *GetBuildingPacketVTable(void) { + static BuildingPacketVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.item_id = BuildingPacket_item_id_impl; + s_vtable.as_BuildingPacketV1 = BuildingPacket_as_BuildingPacketV1_impl; + return &s_vtable; +} +uint32_t BuildingPacket_item_id_impl(BuildingPacketType *this) { + return mol2_unpack_number(&this->cur); +} +BuildingPacketV1Type BuildingPacket_as_BuildingPacketV1_impl( + BuildingPacketType *this) { + BuildingPacketV1Type ret; + mol2_union_t u = mol2_union_unpack(&this->cur); + ret.cur = u.cursor; + ret.t = GetBuildingPacketV1VTable(); + return ret; +} +struct SighashAllType make_SighashAll(mol2_cursor_t *cur) { + SighashAllType ret; + ret.cur = *cur; + ret.t = GetSighashAllVTable(); + return ret; +} +struct SighashAllVTable *GetSighashAllVTable(void) { + static SighashAllVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.message = SighashAll_get_message_impl; + s_vtable.seal = SighashAll_get_seal_impl; + return &s_vtable; +} +MessageType SighashAll_get_message_impl(SighashAllType *this) { + MessageType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 0); + ret.cur = cur; + ret.t = GetMessageVTable(); + return ret; +} +mol2_cursor_t SighashAll_get_seal_impl(SighashAllType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_rawbytes(&re2); + return ret; +} +struct SighashAllOnlyType make_SighashAllOnly(mol2_cursor_t *cur) { + SighashAllOnlyType ret; + ret.cur = *cur; + ret.t = GetSighashAllOnlyVTable(); + return ret; +} +struct SighashAllOnlyVTable *GetSighashAllOnlyVTable(void) { + static SighashAllOnlyVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.seal = SighashAllOnly_get_seal_impl; + return &s_vtable; +} +mol2_cursor_t SighashAllOnly_get_seal_impl(SighashAllOnlyType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_rawbytes(&re2); + return ret; +} +struct SealPairType make_SealPair(mol2_cursor_t *cur) { + SealPairType ret; + ret.cur = *cur; + ret.t = GetSealPairVTable(); + return ret; +} +struct SealPairVTable *GetSealPairVTable(void) { + static SealPairVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.script_hash = SealPair_get_script_hash_impl; + s_vtable.seal = SealPair_get_seal_impl; + return &s_vtable; +} +mol2_cursor_t SealPair_get_script_hash_impl(SealPairType *this) { + mol2_cursor_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_array(&ret2); + return ret; +} +mol2_cursor_t SealPair_get_seal_impl(SealPairType *this) { + mol2_cursor_t ret; + mol2_cursor_t re2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_rawbytes(&re2); + return ret; +} +struct SealPairVecType make_SealPairVec(mol2_cursor_t *cur) { + SealPairVecType ret; + ret.cur = *cur; + ret.t = GetSealPairVecVTable(); + return ret; +} +struct SealPairVecVTable *GetSealPairVecVTable(void) { + static SealPairVecVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.len = SealPairVec_len_impl; + s_vtable.get = SealPairVec_get_impl; + return &s_vtable; +} +uint32_t SealPairVec_len_impl(SealPairVecType *this) { + return mol2_dynvec_length(&this->cur); +} +SealPairType SealPairVec_get_impl(SealPairVecType *this, uint32_t index, + bool *existing) { + SealPairType ret = {0}; + mol2_cursor_res_t res = mol2_dynvec_slice_by_index(&this->cur, index); + if (res.errno != MOL2_OK) { + *existing = false; + return ret; + } else { + *existing = true; + } + ret.cur = res.cur; + ret.t = GetSealPairVTable(); + return ret; +} +struct OtxStartType make_OtxStart(mol2_cursor_t *cur) { + OtxStartType ret; + ret.cur = *cur; + ret.t = GetOtxStartVTable(); + return ret; +} +struct OtxStartVTable *GetOtxStartVTable(void) { + static OtxStartVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.start_input_cell = OtxStart_get_start_input_cell_impl; + s_vtable.start_output_cell = OtxStart_get_start_output_cell_impl; + s_vtable.start_cell_deps = OtxStart_get_start_cell_deps_impl; + s_vtable.start_header_deps = OtxStart_get_start_header_deps_impl; + return &s_vtable; +} +uint32_t OtxStart_get_start_input_cell_impl(OtxStartType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t OtxStart_get_start_output_cell_impl(OtxStartType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t OtxStart_get_start_cell_deps_impl(OtxStartType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 2); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t OtxStart_get_start_header_deps_impl(OtxStartType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 3); + ret = convert_to_Uint32(&ret2); + return ret; +} +struct OtxType make_Otx(mol2_cursor_t *cur) { + OtxType ret; + ret.cur = *cur; + ret.t = GetOtxVTable(); + return ret; +} +struct OtxVTable *GetOtxVTable(void) { + static OtxVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.input_cells = Otx_get_input_cells_impl; + s_vtable.output_cells = Otx_get_output_cells_impl; + s_vtable.cell_deps = Otx_get_cell_deps_impl; + s_vtable.header_deps = Otx_get_header_deps_impl; + s_vtable.message = Otx_get_message_impl; + s_vtable.seals = Otx_get_seals_impl; + return &s_vtable; +} +uint32_t Otx_get_input_cells_impl(OtxType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 0); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t Otx_get_output_cells_impl(OtxType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 1); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t Otx_get_cell_deps_impl(OtxType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 2); + ret = convert_to_Uint32(&ret2); + return ret; +} +uint32_t Otx_get_header_deps_impl(OtxType *this) { + uint32_t ret; + mol2_cursor_t ret2 = mol2_table_slice_by_index(&this->cur, 3); + ret = convert_to_Uint32(&ret2); + return ret; +} +MessageType Otx_get_message_impl(OtxType *this) { + MessageType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 4); + ret.cur = cur; + ret.t = GetMessageVTable(); + return ret; +} +SealPairVecType Otx_get_seals_impl(OtxType *this) { + SealPairVecType ret; + mol2_cursor_t cur = mol2_table_slice_by_index(&this->cur, 5); + ret.cur = cur; + ret.t = GetSealPairVecVTable(); + return ret; +} +#endif // MOLECULEC_C2_DECLARATION_ONLY + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // _COBUILD_BASIC_MOL2_API2_H_ diff --git a/c/cobuild_top_level_mol2.h b/c/cobuild_top_level_mol2.h new file mode 100644 index 0000000..41b3a9d --- /dev/null +++ b/c/cobuild_top_level_mol2.h @@ -0,0 +1,102 @@ + +#ifndef _COBUILD_TOP_LEVEL_MOL2_API2_H_ +#define _COBUILD_TOP_LEVEL_MOL2_API2_H_ + +#ifndef MOLECULEC2_VERSION +#define MOLECULEC2_VERSION 7002 +#endif +#ifndef MOLECULE2_API_VERSION_MIN +#define MOLECULE2_API_VERSION_MIN 5000 +#endif + +#include "molecule2_reader.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +// ----forward declaration-------- +struct WitnessLayoutType; +struct WitnessLayoutVTable; +struct WitnessLayoutVTable *GetWitnessLayoutVTable(void); +struct WitnessLayoutType make_WitnessLayout(mol2_cursor_t *cur); +uint32_t WitnessLayout_item_id_impl(struct WitnessLayoutType *); +struct SighashAllType WitnessLayout_as_SighashAll_impl( + struct WitnessLayoutType *); +struct SighashAllOnlyType WitnessLayout_as_SighashAllOnly_impl( + struct WitnessLayoutType *); +struct OtxType WitnessLayout_as_Otx_impl(struct WitnessLayoutType *); +struct OtxStartType WitnessLayout_as_OtxStart_impl(struct WitnessLayoutType *); + +// ----definition----------------- +typedef struct WitnessLayoutVTable { + uint32_t (*item_id)(struct WitnessLayoutType *); + struct SighashAllType (*as_SighashAll)(struct WitnessLayoutType *); + struct SighashAllOnlyType (*as_SighashAllOnly)(struct WitnessLayoutType *); + struct OtxType (*as_Otx)(struct WitnessLayoutType *); + struct OtxStartType (*as_OtxStart)(struct WitnessLayoutType *); +} WitnessLayoutVTable; +typedef struct WitnessLayoutType { + mol2_cursor_t cur; + WitnessLayoutVTable *t; +} WitnessLayoutType; + +#ifndef MOLECULEC_C2_DECLARATION_ONLY + +// ----implementation------------- +struct WitnessLayoutType make_WitnessLayout(mol2_cursor_t *cur) { + WitnessLayoutType ret; + ret.cur = *cur; + ret.t = GetWitnessLayoutVTable(); + return ret; +} +struct WitnessLayoutVTable *GetWitnessLayoutVTable(void) { + static WitnessLayoutVTable s_vtable; + static int inited = 0; + if (inited) return &s_vtable; + s_vtable.item_id = WitnessLayout_item_id_impl; + s_vtable.as_SighashAll = WitnessLayout_as_SighashAll_impl; + s_vtable.as_SighashAllOnly = WitnessLayout_as_SighashAllOnly_impl; + s_vtable.as_Otx = WitnessLayout_as_Otx_impl; + s_vtable.as_OtxStart = WitnessLayout_as_OtxStart_impl; + return &s_vtable; +} +uint32_t WitnessLayout_item_id_impl(WitnessLayoutType *this) { + return mol2_unpack_number(&this->cur); +} +SighashAllType WitnessLayout_as_SighashAll_impl(WitnessLayoutType *this) { + SighashAllType ret; + mol2_union_t u = mol2_union_unpack(&this->cur); + ret.cur = u.cursor; + ret.t = GetSighashAllVTable(); + return ret; +} +SighashAllOnlyType WitnessLayout_as_SighashAllOnly_impl( + WitnessLayoutType *this) { + SighashAllOnlyType ret; + mol2_union_t u = mol2_union_unpack(&this->cur); + ret.cur = u.cursor; + ret.t = GetSighashAllOnlyVTable(); + return ret; +} +OtxType WitnessLayout_as_Otx_impl(WitnessLayoutType *this) { + OtxType ret; + mol2_union_t u = mol2_union_unpack(&this->cur); + ret.cur = u.cursor; + ret.t = GetOtxVTable(); + return ret; +} +OtxStartType WitnessLayout_as_OtxStart_impl(WitnessLayoutType *this) { + OtxStartType ret; + mol2_union_t u = mol2_union_unpack(&this->cur); + ret.cur = u.cursor; + ret.t = GetOtxStartVTable(); + return ret; +} +#endif // MOLECULEC_C2_DECLARATION_ONLY + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // _COBUILD_TOP_LEVEL_MOL2_API2_H_ diff --git a/c/dump_secp256k1_data.c b/c/dump_secp256k1_data.c index 83f6065..f91ffb3 100644 --- a/c/dump_secp256k1_data.c +++ b/c/dump_secp256k1_data.c @@ -34,22 +34,23 @@ int main(int argc, char* argv[]) { fprintf(fp, "#define CKB_SECP256K1_DATA_PRE_SIZE %ld\n", pre_size); fprintf(fp, "#define CKB_SECP256K1_DATA_PRE128_SIZE %ld\n", pre128_size); - blake2b_state blake2b_ctx; - uint8_t hash[32]; - blake2b_init(&blake2b_ctx, 32); - blake2b_update(&blake2b_ctx, secp256k1_ecmult_static_pre_context, pre_size); - blake2b_update(&blake2b_ctx, secp256k1_ecmult_static_pre128_context, - pre128_size); - blake2b_final(&blake2b_ctx, hash, 32); - - fprintf(fp, "static uint8_t ckb_secp256k1_data_hash[32] = {\n "); - for (int i = 0; i < 32; i++) { - fprintf(fp, "%u", hash[i]); - if (i != 31) { + fprintf(fp, "static uint8_t ckb_secp256k1_data[] = {\n "); + unsigned char* p = (unsigned char*)secp256k1_ecmult_static_pre_context; + for (int i = 0; i < pre_size; i++) { + fprintf(fp, "0x%02x", p[i]); + fprintf(fp, ", "); + } + fprintf(fp, "\n"); + p = (unsigned char*)secp256k1_ecmult_static_pre128_context; + for (int i = 0; i < pre128_size; i++) { + fprintf(fp, "0x%02x", p[i]); + if (i != (pre128_size -1)) { fprintf(fp, ", "); } } + fprintf(fp, "\n};\n"); + fprintf(fp, "#endif\n"); fclose(fp); diff --git a/c/dump_secp256k1_data_20210801.c b/c/dump_secp256k1_data_20210801.c deleted file mode 100644 index 10f4236..0000000 --- a/c/dump_secp256k1_data_20210801.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include "blake2b.h" - -/* - * We are including secp256k1 implementation directly so gcc can strip - * unused functions. For some unknown reasons, if we link in libsecp256k1.a - * directly, the final binary will include all functions rather than those used. - */ -#define HAVE_CONFIG_H 1 -#include - -#define ERROR_IO -1 - -int main(int argc, char* argv[]) { - size_t pre_size = sizeof(secp256k1_ecmult_static_pre_context); - size_t pre128_size = sizeof(secp256k1_ecmult_static_pre128_context); - - FILE* fp_data = fopen("build/secp256k1_data_20210801", "wb"); - if (!fp_data) { - return ERROR_IO; - } - fwrite(secp256k1_ecmult_static_pre_context, pre_size, 1, fp_data); - fwrite(secp256k1_ecmult_static_pre128_context, pre128_size, 1, fp_data); - fclose(fp_data); - - FILE* fp = fopen("build/secp256k1_data_info_20210801.h", "w"); - if (!fp) { - return ERROR_IO; - } - - fprintf(fp, "#ifndef CKB_SECP256K1_DATA_INFO_H_\n"); - fprintf(fp, "#define CKB_SECP256K1_DATA_INFO_H_\n"); - fprintf(fp, "#define CKB_SECP256K1_DATA_SIZE %ld\n", pre_size + pre128_size); - fprintf(fp, "#define CKB_SECP256K1_DATA_PRE_SIZE %ld\n", pre_size); - fprintf(fp, "#define CKB_SECP256K1_DATA_PRE128_SIZE %ld\n", pre128_size); - - blake2b_state blake2b_ctx; - uint8_t hash[32]; - blake2b_init(&blake2b_ctx, 32); - blake2b_update(&blake2b_ctx, secp256k1_ecmult_static_pre_context, pre_size); - blake2b_update(&blake2b_ctx, secp256k1_ecmult_static_pre128_context, - pre128_size); - blake2b_final(&blake2b_ctx, hash, 32); - - fprintf(fp, "static uint8_t ckb_secp256k1_data_hash[32] = {\n "); - for (int i = 0; i < 32; i++) { - fprintf(fp, "%u", hash[i]); - if (i != 31) { - fprintf(fp, ", "); - } - } - fprintf(fp, "\n};\n"); - fprintf(fp, "#endif\n"); - fclose(fp); - - return 0; -} diff --git a/c/mol2_utils.h b/c/mol2_utils.h new file mode 100644 index 0000000..e625d89 --- /dev/null +++ b/c/mol2_utils.h @@ -0,0 +1,348 @@ +/* + * This file contains handy utilities for molecule-c2. Ideally most of + * this file should be part of molecule-c2 itself. + */ + +#ifndef MOL2_UTILS +#define MOL2_UTILS + +#include "blake2b.h" +#include "ckb_consts.h" +#include "ckb_syscall_apis.h" +#include "molecule2_reader.h" + +// Given a data source, this macro extracts the start of cache buffer +#define MOL2_CACHE_PTR(data_source) \ + (((mol2_data_source_t *)(data_source))->cache) + +typedef uint32_t(read_from_t)(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset); + +static uint32_t read_from_witness(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset) { + int err; + uint64_t output_len = len; + err = ckb_load_witness(ptr, &output_len, offset, arg[0], arg[1]); + if (err != 0) { + return 0; + } + if (output_len > len) { + return len; + } else { + return (uint32_t)output_len; + } +} + +static uint32_t read_from_cell_data(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset) { + int err; + uint64_t output_len = len; + err = ckb_load_cell_data(ptr, &output_len, offset, arg[0], arg[1]); + if (err != 0) { + return 0; + } + if (output_len > len) { + return len; + } else { + return (uint32_t)output_len; + } +} + +static uint32_t read_from_cell(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset) { + int err; + uint64_t output_len = len; + err = ckb_load_cell(ptr, &output_len, offset, arg[0], arg[1]); + if (err != 0) { + return 0; + } + if (output_len > len) { + return len; + } else { + return (uint32_t)output_len; + } +} + +static uint32_t read_from_tx(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset) { + int err; + uint64_t output_len = len; + err = ckb_load_transaction(ptr, &output_len, offset); + if (err != 0) { + return 0; + } + if (output_len > len) { + return len; + } else { + return (uint32_t)output_len; + } +} + +static uint32_t read_from_script(uintptr_t arg[], uint8_t *ptr, uint32_t len, + uint32_t offset) { + int err; + uint64_t output_len = len; + err = ckb_load_script(ptr, &output_len, offset); + if (err != 0) { + return 0; + } + if (output_len > len) { + return len; + } else { + return (uint32_t)output_len; + } +} + +static void ckb_new_cursor_with_data(mol2_cursor_t *cursor, uint32_t total_len, + read_from_t read_from, + uint8_t *data_source, uint32_t cache_len, + size_t index, size_t source, + uint32_t cached_size) { + cursor->offset = 0; + cursor->size = (uint32_t)total_len; + + mol2_data_source_t *ptr = (mol2_data_source_t *)data_source; + + ptr->read = read_from; + ptr->total_size = total_len; + ptr->args[0] = index; + ptr->args[1] = source; + + ptr->cache_size = cached_size; + ptr->start_point = 0; + ptr->max_cache_size = cache_len; + + cursor->data_source = ptr; +} + +static int ckb_new_witness_cursor(mol2_cursor_t *cursor, uint8_t *data_source, + uint32_t cache_len, size_t index, + size_t source) { + int err; + + // Use a single syscall to fetch cached data and total length + uint64_t len = cache_len; + err = ckb_load_witness(MOL2_CACHE_PTR(data_source), &len, 0, index, source); + if (err != 0) { + return err; + } + uint32_t cache_size = (uint32_t)len; + if (cache_size > cache_len) { + cache_size = cache_len; + } + ckb_new_cursor_with_data(cursor, len, read_from_witness, data_source, + cache_len, index, source, cache_size); + + return 0; +} + +typedef int(cursor_accessor_t)(const uint8_t *data, size_t len, void *context); +static int ckb_access_cursor(mol2_cursor_t cursor, cursor_accessor_t accessor, + void *context) { + int err = 0; + uint8_t batch[MAX_CACHE_SIZE]; + while (true) { + uint32_t read_len = mol2_read_at(&cursor, batch, sizeof(batch)); + err = accessor(batch, read_len, context); + if (err != 0) { + return err; + } + // adjust cursor + mol2_add_offset(&cursor, read_len); + mol2_sub_size(&cursor, read_len); + mol2_validate(&cursor); + if (cursor.size == 0) { + break; + } + } + return 0; +} + +#ifndef BLAKE2B_UPDATE +#define BLAKE2B_UPDATE blake2b_update +#endif + +static int _ckb_cursor_blake2b_hasher(const uint8_t *data, size_t len, + void *context) { + blake2b_state *state = (blake2b_state *)context; + BLAKE2B_UPDATE(state, data, len); + return 0; +} + +static int ckb_hash_cursor(blake2b_state *ctx, mol2_cursor_t cursor) { + // one batch to drain whole cache perfectly + // tested by test_input_cell_data_size_0 + // test_input_cell_data_size_1 + // test_input_cell_data_size_2048 + // test_input_cell_data_size_2049 + // test_input_cell_data_size_500k + return ckb_access_cursor(cursor, _ckb_cursor_blake2b_hasher, ctx); +} + +static int ckb_compare_cursor(mol2_cursor_t a, mol2_cursor_t b, int *result) { + if (a.size < b.size) { + *result = -1; + return 0; + } else if (a.size > b.size) { + *result = 1; + return 0; + } + + uint8_t batch_a[MAX_CACHE_SIZE]; + uint8_t batch_b[MAX_CACHE_SIZE]; + while (true) { + uint32_t read_len_a = mol2_read_at(&a, batch_a, sizeof(batch_a)); + uint32_t read_len_b = mol2_read_at(&b, batch_b, sizeof(batch_b)); + if (read_len_a != read_len_b) { + return MOL2_ERR_DATA; + } + int ret = memcmp(batch_a, batch_b, read_len_a); + if (ret != 0) { + *result = ret; + return 0; + } + + // adjust cursors + mol2_add_offset(&a, read_len_a); + mol2_sub_size(&a, read_len_a); + mol2_validate(&a); + mol2_add_offset(&b, read_len_b); + mol2_sub_size(&b, read_len_b); + mol2_validate(&b); + if (a.size == 0) { + break; + } + } + + *result = 0; + return 0; +} + +static int try_union_unpack_id(const mol2_cursor_t *cursor, uint32_t *id) { + uint32_t len = mol2_read_at(cursor, (uint8_t *)id, 4); + if (len != 4) { + // tested by: + // tested_by_no_cobuild_append_sighash_all + // tested_by_insert_witness_less_4_before_sighashall + return MOL2_ERR_DATA; + } + return CKB_SUCCESS; +} + +#ifndef MOL2_UTILS_CACHE_TX_SIZE +#define MOL2_UTILS_CACHE_TX_SIZE 65536 +#endif + +#ifndef MOL2_UTILS_CACHE_SCRIPT_SIZE +#define MOL2_UTILS_CACHE_SCRIPT_SIZE 1024 +#endif + +typedef struct { + uint8_t tx_source[MOL2_DATA_SOURCE_LEN(MOL2_UTILS_CACHE_TX_SIZE)]; + mol2_cursor_t tx_cursor; + TransactionType tx; + + uint8_t + current_script_source[MOL2_DATA_SOURCE_LEN(MOL2_UTILS_CACHE_SCRIPT_SIZE)]; + mol2_cursor_t current_script_cursor; + ScriptType current_script; + + uint8_t tx_hash[32]; + uint8_t current_script_hash[32]; + + void *script_specific_data; +} Env; + +static int ckb_env_initialize(Env *env) { + int err; + { + uint64_t tx_len = MOL2_UTILS_CACHE_TX_SIZE; + err = ckb_load_transaction(MOL2_CACHE_PTR(env->tx_source), &tx_len, 0); + if (err != 0) { + return err; + } + uint32_t cache_size = (uint32_t)tx_len; + if (cache_size > MOL2_UTILS_CACHE_TX_SIZE) { + cache_size = MOL2_UTILS_CACHE_TX_SIZE; + } + + ckb_new_cursor_with_data(&env->tx_cursor, tx_len, read_from_tx, + env->tx_source, MOL2_UTILS_CACHE_TX_SIZE, 0, 0, + cache_size); + + env->tx = make_Transaction(&env->tx_cursor); + } + + { + uint64_t script_len = MOL2_UTILS_CACHE_SCRIPT_SIZE; + err = ckb_load_script(MOL2_CACHE_PTR(env->current_script_source), + &script_len, 0); + if (err != 0) { + return err; + } + uint32_t cache_size = (uint32_t)script_len; + if (cache_size > MOL2_UTILS_CACHE_SCRIPT_SIZE) { + cache_size = MOL2_UTILS_CACHE_SCRIPT_SIZE; + } + + ckb_new_cursor_with_data(&env->current_script_cursor, script_len, + read_from_script, env->current_script_source, + MOL2_UTILS_CACHE_SCRIPT_SIZE, 0, 0, + MOL2_UTILS_CACHE_SCRIPT_SIZE); + + env->current_script = make_Script(&env->current_script_cursor); + } + + { + uint64_t tx_hash_len = 32; + err = ckb_load_tx_hash(env->tx_hash, &tx_hash_len, 0); + if (err != 0) { + return err; + } + if (tx_hash_len != 32) { + return MOL2_ERR_DATA; + } + } + + { + uint64_t script_hash_len = 32; + err = ckb_load_script_hash(env->current_script_hash, &script_hash_len, 0); + if (err != 0) { + return err; + } + if (script_hash_len != 32) { + return MOL2_ERR_DATA; + } + } + + env->script_specific_data = NULL; + + return 0; +} + +static inline mol2_cursor_t mol2_cursor_slice(const mol2_cursor_t *cur, + uint32_t offset, + uint32_t new_size) { + uint32_t shrinked_size; + // This way we can ensure that the new size will be no larger than original + // cursor + if (__builtin_sub_overflow(cur->size, new_size, &shrinked_size)) { + MOL2_PANIC(MOL2_ERR_OVERFLOW); + } + mol2_cursor_t res = *cur; + mol2_add_offset(&res, offset); + mol2_sub_size(&res, shrinked_size); + mol2_validate(&res); + return res; +} + +static inline mol2_cursor_t mol2_cursor_slice_start(const mol2_cursor_t *cur, + uint32_t offset) { + mol2_cursor_t res = *cur; + mol2_add_offset(&res, offset); + mol2_sub_size(&res, offset); + mol2_validate(&res); + return res; +} + +#endif /* MOL2_UTILS */ diff --git a/c/molecule2_verify.h b/c/molecule2_verify.h new file mode 100644 index 0000000..fec7ac9 --- /dev/null +++ b/c/molecule2_verify.h @@ -0,0 +1,230 @@ +#ifndef __MOLECULE2_VERIFY_H__ +#define __MOLECULE2_VERIFY_H__ + +#include "cobuild_basic_mol2.h" +#include "cobuild_top_level_mol2.h" +#include "molecule2_reader.h" + +#ifndef BLAKE2B_BLOCK_SIZE +#define BLAKE2B_BLOCK_SIZE 32 +#endif // BLAKE2B_BLOCK_SIZE + +typedef enum WitnessLayoutId { + WitnessLayoutSighashAll = 4278190081, + WitnessLayoutSighashAllOnly = 4278190082, + WitnessLayoutOtx = 4278190083, + WitnessLayoutOtxStart = 4278190084, +} WitnessLayoutId; + +int verify_WitnessArgs(WitnessArgsType *witness); +int verify_WitnessLayout(WitnessLayoutType *witness, bool recursive); + +#ifndef MOLECULEC_C2_DECLARATION_ONLY + +// If it is get by other struct, not need to verify +int verify_Bytes(mol2_cursor_t cur) { return mol2_fixvec_verify(&cur, 1); } + +int verify_BytesOpt(mol2_cursor_t cur) { + int err = MOL2_OK; + BytesOptType bytes_opt = make_BytesOpt(&cur); + + if (bytes_opt.t->is_some(&bytes_opt)) { + CHECK(verify_Bytes(bytes_opt.cur)); + } +exit: + return err; +} + +int verify_WitnessArgs(WitnessArgsType *witness) { + int err = MOL2_OK; + + BytesOptType lock = witness->t->lock(witness); + CHECK(verify_BytesOpt(lock.cur)); + BytesOptType input_type = witness->t->input_type(witness); + CHECK(verify_BytesOpt(input_type.cur)); + BytesOptType output_type = witness->t->output_type(witness); + CHECK(verify_BytesOpt(output_type.cur)); + +exit: + return err; +} + +int verify_Action(ActionType *action) { + int err = MOL2_OK; + mol2_cursor_t data = mol2_table_slice_by_index(&action->cur, 2); + CHECK(verify_Bytes(data)); + + mol2_cursor_t script_hash = action->t->script_hash(action); + CHECK(mol2_verify_fixed_size(&script_hash, BLAKE2B_BLOCK_SIZE)); + + mol2_cursor_t script_info_hash = action->t->script_info_hash(action); + CHECK(mol2_verify_fixed_size(&script_info_hash, BLAKE2B_BLOCK_SIZE)); + +exit: + return err; +} + +int verify_ActionVec(ActionVecType *actions) { + int err = MOL2_OK; + + uint32_t len = actions->t->len(actions); + for (uint32_t i = 0; i < len; i++) { + bool existing = false; + ActionType action = actions->t->get(actions, i, &existing); + CHECK2(existing, MOL2_ERR_INDEX_OUT_OF_BOUNDS); + CHECK(verify_Action(&action)); + } + +exit: + return err; +} + +int verify_Message(MessageType *message) { + int err = MOL2_OK; + ActionVecType actions = message->t->actions(message); + CHECK(verify_ActionVec(&actions)); + +exit: + return err; +} + +int verify_SealPair(SealPairType *seal_pair) { + int err = MOL2_OK; + mol2_cursor_t script_hash = seal_pair->t->script_hash(seal_pair); + CHECK(mol2_verify_fixed_size(&script_hash, BLAKE2B_BLOCK_SIZE)); + + mol2_cursor_t seal = mol2_table_slice_by_index(&seal_pair->cur, 1); + CHECK(verify_Bytes(seal)); + +exit: + return err; +} + +int verify_SealPairVec(SealPairVecType *seals) { + int err = MOL2_OK; + uint32_t len = seals->t->len(seals); + for (uint32_t i = 0; i < len; i++) { + bool existing = false; + SealPairType seal_pair = seals->t->get(seals, i, &existing); + CHECK2(existing, MOL2_ERR_INDEX_OUT_OF_BOUNDS); + CHECK(verify_SealPair(&seal_pair)); + } + +exit: + return err; +} + +int verify_SighashAll(SighashAllType *sighash_all) { + int err = MOL2_OK; + MessageType message = sighash_all->t->message(sighash_all); + CHECK(verify_Message(&message)); + + mol2_cursor_t seal = mol2_table_slice_by_index(&sighash_all->cur, 1); + CHECK(verify_Bytes(seal)); + +exit: + return err; +} + +int verify_SighashAllOnly(SighashAllOnlyType *signhash_all_only) { + int err = MOL2_OK; + mol2_cursor_t seal = mol2_table_slice_by_index(&signhash_all_only->cur, 0); + CHECK(verify_Bytes(seal)); + +exit: + return err; +} + +int verify_Otx(OtxType *otx) { + int err = MOL2_OK; + mol2_cursor_t input_cells = mol2_table_slice_by_index(&otx->cur, 0); + CHECK(mol2_verify_fixed_size(&input_cells, MOL2_NUM_T_SIZE)); + mol2_cursor_t output_cells = mol2_table_slice_by_index(&otx->cur, 1); + CHECK(mol2_verify_fixed_size(&output_cells, MOL2_NUM_T_SIZE)); + mol2_cursor_t cell_deps = mol2_table_slice_by_index(&otx->cur, 2); + CHECK(mol2_verify_fixed_size(&cell_deps, MOL2_NUM_T_SIZE)); + mol2_cursor_t header_deps = mol2_table_slice_by_index(&otx->cur, 3); + CHECK(mol2_verify_fixed_size(&header_deps, MOL2_NUM_T_SIZE)); + MessageType message = Otx_get_message_impl(otx); + CHECK(verify_Message(&message)); + SealPairVecType seals = Otx_get_seals_impl(otx); + CHECK(verify_SealPairVec(&seals)); + +exit: + return err; +} + +int verify_OtxStart(OtxStartType *otx_start) { + int err = MOL2_OK; + mol2_cursor_t input_cells = mol2_table_slice_by_index(&otx_start->cur, 0); + CHECK(mol2_verify_fixed_size(&input_cells, MOL2_NUM_T_SIZE)); + mol2_cursor_t output_cells = mol2_table_slice_by_index(&otx_start->cur, 1); + CHECK(mol2_verify_fixed_size(&output_cells, MOL2_NUM_T_SIZE)); + mol2_cursor_t cell_deps = mol2_table_slice_by_index(&otx_start->cur, 2); + CHECK(mol2_verify_fixed_size(&cell_deps, MOL2_NUM_T_SIZE)); + mol2_cursor_t header_deps = mol2_table_slice_by_index(&otx_start->cur, 3); + CHECK(mol2_verify_fixed_size(&header_deps, MOL2_NUM_T_SIZE)); +exit: + return err; +} + +int get_union_id(mol2_cursor_t *cur, uint32_t *union_id) { + uint32_t len = mol2_read_at(cur, (uint8_t *)union_id, MOL2_NUM_T_SIZE); + if (len != MOL2_NUM_T_SIZE) { + return MOL2_ERR_OVERFLOW; + } + + return MOL2_OK; +} + +int verify_WitnessLayout(WitnessLayoutType *witness, bool recursive) { + int err = MOL2_OK; + uint32_t union_id = 0; + err = get_union_id(&witness->cur, &union_id); + CHECK(err); + switch (union_id) { + case WitnessLayoutSighashAll: { + if (recursive) { + SighashAllType sighash_all = witness->t->as_SighashAll(witness); + err = verify_SighashAll(&sighash_all); + CHECK(err); + } + break; + } + case WitnessLayoutSighashAllOnly: { + if (recursive) { + SighashAllOnlyType sighash_all_only = + witness->t->as_SighashAllOnly(witness); + err = verify_SighashAllOnly(&sighash_all_only); + CHECK(err); + } + break; + } + case WitnessLayoutOtx: { + if (recursive) { + OtxType otx = witness->t->as_Otx(witness); + err = verify_Otx(&otx); + CHECK(err); + } + break; + } + case WitnessLayoutOtxStart: { + if (recursive) { + OtxStartType otx_start = witness->t->as_OtxStart(witness); + err = verify_OtxStart(&otx_start); + CHECK(err); + } + break; + } + default: { + return MOL2_ERR_UNKNOWN_ITEM; + } + } + +exit: + return err; +} + +#endif // MOLECULEC_C2_DECLARATION_ONLY + +#endif diff --git a/c/omni_lock.c b/c/omni_lock.c index 1e092b7..c519e3e 100644 --- a/c/omni_lock.c +++ b/c/omni_lock.c @@ -1,19 +1,14 @@ -// uncomment to enable printf in CKB-VM -// #define CKB_C_STDLIB_PRINTF +// clang-format off +#include +#include // it's used by blockchain-api2.h, the behavior when panic #ifndef MOL2_EXIT #define MOL2_EXIT ckb_exit #endif int ckb_exit(signed char); -// in secp256k1_ctz64_var: we don't have __builtin_ctzl in gcc for RISC-V -#define __builtin_ctzl secp256k1_ctz64_var_debruijn - -// clang-format off -#include -#include "blockchain-api2.h" #define MOLECULEC_VERSION 7000 -#include "blockchain.h" +#include "blockchain-api2.h" #include "ckb_consts.h" #if defined(CKB_USE_SIM) @@ -23,23 +18,21 @@ int ckb_exit(signed char); #else #include "ckb_syscalls.h" #endif -// secp256k1_helper_20210801.h is not part of ckb-c-stdlib, can't be included in ckb_identity.h -// An upgraded version is provided. -#include "secp256k1_helper_20210801.h" +#include "secp256k1_helper.h" +// CHECK is defined in secp256k1 +#undef CHECK #include "ckb_swappable_signatures.h" - #include "ckb_identity.h" #include "ckb_smt.h" -// CHECK is defined in secp256k1 -#undef CHECK #include "rce.h" #include "omni_lock_mol2.h" +#include "molecule2_verify.h" #include "omni_lock_acp.h" #include "omni_lock_time_lock.h" #include "omni_lock_supply.h" - +#include "cobuild.h" // clang-format on #define SCRIPT_SIZE 32768 @@ -77,14 +70,14 @@ typedef struct ArgsType { uint64_t since; bool has_acp; - int ckb_minimum; // Used for ACP - int udt_minimum; // used for ACP + uint8_t ckb_minimum; // Used for ACP + uint8_t udt_minimum; // used for ACP bool has_supply; uint8_t info_cell[32]; // type script hash } ArgsType; -// parsed from lock in witness +// parsed from lock in witness or seal typedef struct WitnessLockType { bool has_identity; bool has_signature; @@ -99,6 +92,8 @@ typedef struct WitnessLockType { SmtProofEntryVecType proofs; } WitnessLockType; +uint8_t g_code_buff[MAX_CODE_SIZE] __attribute__((aligned(RISCV_PGSIZE))); + // make compiler happy int make_cursor_from_witness(WitnessArgsType *witness, bool *_input) { return -1; @@ -138,41 +133,26 @@ bool is_memory_enough(mol_seg_t seg, const uint8_t *cur, uint32_t len) { // // -int parse_args(ArgsType *args) { +int parse_args(ScriptType script, ArgsType *args) { int err = 0; - uint8_t script[SCRIPT_SIZE]; - uint64_t len = SCRIPT_SIZE; - err = ckb_checked_load_script(script, &len, 0); - CHECK(err); - mol_seg_t script_seg; - script_seg.ptr = script; - script_seg.size = (mol_num_t)len; - - mol_errno mol_err = MolReader_Script_verify(&script_seg, false); - CHECK2(mol_err == MOL_OK, ERROR_ENCODING); - - mol_seg_t args_seg = MolReader_Script_get_args(&script_seg); - mol_seg_t seg = MolReader_Bytes_raw_bytes(&args_seg); - - uint8_t *cur = seg.ptr; + mol2_cursor_t script_args = script.t->args(&script); // parse flags - CHECK2(is_memory_enough(seg, cur, 1), ERROR_ARGS_FORMAT); - uint8_t flags = *cur; - args->id.flags = flags; - cur = safe_move_to(seg, cur, 1); - CHECK2(cur != NULL, ERROR_ARGS_FORMAT); + CHECK2(script_args.size >= 1, ERROR_ARGS_FORMAT); + CHECK2(mol2_read_at(&script_args, &args->id.flags, 1) == 1, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 1); // parse blake160 - CHECK2(is_memory_enough(seg, cur, 20), ERROR_ARGS_FORMAT); - memcpy(args->id.id, cur, BLAKE160_SIZE); - cur = safe_move_to(seg, cur, 20); - CHECK2(cur != NULL, ERROR_ARGS_FORMAT); + CHECK2(script_args.size >= 20, ERROR_ARGS_FORMAT); + CHECK2(mol2_read_at(&script_args, args->id.id, 20) == 20, ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 20); - CHECK2(is_memory_enough(seg, cur, 1), ERROR_ARGS_FORMAT); - args->omni_lock_flags = *cur; - cur = safe_move_to(seg, cur, 1); + CHECK2(script_args.size >= 1, ERROR_ARGS_FORMAT); + CHECK2(mol2_read_at(&script_args, &args->omni_lock_flags, 1) == 1, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 1); args->has_omni_root = args->omni_lock_flags & OMNI_ROOT_MASK; args->has_acp = args->omni_lock_flags & ACP_MASK; @@ -192,86 +172,38 @@ int parse_args(ArgsType *args) { expected_size += 32; } - if (expected_size == 0) { - CHECK2(cur == NULL, ERROR_ARGS_FORMAT); - } else { - CHECK2(cur != NULL, ERROR_ARGS_FORMAT); - CHECK2(is_memory_enough(seg, cur, expected_size), ERROR_ARGS_FORMAT); + CHECK2(script_args.size == expected_size, ERROR_ARGS_FORMAT); + if (expected_size > 0) { if (args->has_omni_root) { - memcpy(args->omni_root, cur, 32); - cur += 32; // it's safe to move, already checked + CHECK2(mol2_read_at(&script_args, args->omni_root, 32) == 32, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 32); } if (args->has_acp) { - args->ckb_minimum = cur[0]; - args->udt_minimum = cur[1]; - cur += 2; + CHECK2(mol2_read_at(&script_args, &args->ckb_minimum, 1) == 1, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 1); + CHECK2(mol2_read_at(&script_args, &args->udt_minimum, 1) == 1, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 1); } if (args->has_since) { - args->since = *(uint64_t *)cur; - cur += 8; + CHECK2(mol2_read_at(&script_args, (uint8_t *)(&args->since), 8) == 8, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 8); } if (args->has_supply) { - memcpy(args->info_cell, cur, 32); - cur += 32; + CHECK2(mol2_read_at(&script_args, args->info_cell, 32) == 32, + ERROR_ARGS_FORMAT); + script_args = mol2_cursor_slice_start(&script_args, 32); } - CHECK2(cur == (seg.ptr + seg.size), ERROR_INVALID_MOL_FORMAT); + CHECK2(script_args.size == 0, ERROR_INVALID_MOL_FORMAT); } exit: return err; } -static uint32_t read_from_witness(uintptr_t arg[], uint8_t *ptr, uint32_t len, - uint32_t offset) { - int err; - uint64_t output_len = len; - err = ckb_load_witness(ptr, &output_len, offset, arg[0], arg[1]); - if (err != 0) { - return 0; - } - if (output_len > len) { - return len; - } else { - return (uint32_t)output_len; - } -} - -uint8_t g_witness_data_source[DEFAULT_DATA_SOURCE_LENGTH]; -int make_witness(WitnessArgsType *witness) { - int err = 0; - uint64_t witness_len = 0; - size_t source = CKB_SOURCE_GROUP_INPUT; - err = ckb_load_witness(NULL, &witness_len, 0, 0, source); - // when witness is missing, empty or not accessible, make it zero length. - // don't fail, because owner lock without omni doesn't require witness. - // when it's zero length, any further actions on witness will fail. - if (err != 0) { - witness_len = 0; - } - - mol2_cursor_t cur; - - cur.offset = 0; - cur.size = (mol_num_t)witness_len; - - mol2_data_source_t *ptr = (mol2_data_source_t *)g_witness_data_source; - - ptr->read = read_from_witness; - ptr->total_size = (uint32_t)witness_len; - // pass index and source as args - ptr->args[0] = 0; - ptr->args[1] = source; - - ptr->cache_size = 0; - ptr->start_point = 0; - ptr->max_cache_size = MAX_CACHE_SIZE; - cur.data_source = ptr; - - *witness = make_WitnessArgs(&cur); - - return 0; -} - int smt_verify_identity(CkbIdentityType *id, SmtProofEntryVecType *proofs, RceState *rce_state) { int err = 0; @@ -313,29 +245,14 @@ int smt_verify_identity(CkbIdentityType *id, SmtProofEntryVecType *proofs, return err; } -int parse_witness_lock(WitnessLockType *witness_lock) { +static int parse_witness_lock(WitnessLockType *witness_lock, + mol2_cursor_t *seal) { int err = 0; witness_lock->has_signature = false; witness_lock->has_identity = false; witness_lock->has_proofs = false; - - bool witness_existing = false; - - WitnessArgsType witness_args; - err = make_witness(&witness_args); - CHECK(err); - witness_existing = witness_args.cur.size > 0; - - // witness or witness lock can be empty if owner lock without omni is used - if (!witness_existing) return err; - - BytesOptType mol_lock = witness_args.t->lock(&witness_args); - if (mol_lock.t->is_none(&mol_lock)) return err; - - mol2_cursor_t mol_lock_bytes = mol_lock.t->unwrap(&mol_lock); // convert Bytes to OmniLockWitnessLock - OmniLockWitnessLockType mol_witness_lock = - make_OmniLockWitnessLock(&mol_lock_bytes); + OmniLockWitnessLockType mol_witness_lock = make_OmniLockWitnessLock(seal); IdentityOptType identity_opt = mol_witness_lock.t->omni_identity(&mol_witness_lock); witness_lock->has_identity = identity_opt.t->is_some(&identity_opt); @@ -377,50 +294,41 @@ int parse_witness_lock(WitnessLockType *witness_lock) { return err; } -#ifdef CKB_USE_SIM -int simulator_main() { -#else -int main() { -#endif - // don't move code_buff into global variable. It doesn't work. - // it's a ckb-vm bug: the global variable will be freezed: - // https://github.com/nervosnetwork/ckb-vm/blob/d43f58d6bf8cc6210721fdcdb6e5ecba513ade0c/src/machine/elf_adaptor.rs#L28-L32 - // The code can't be loaded into frozen memory. - uint8_t code_buff[MAX_CODE_SIZE] __attribute__((aligned(RISCV_PGSIZE))); - +// smh is short for signing message hash +int omnilock_entry(const Env *env, const uint8_t *smh, mol2_cursor_t seal) { int err = 0; - WitnessLockType witness_lock = {0}; - ArgsType args = {0}; + // this identity can be either from witness lock (witness_lock.id) or script // args (args.id) CkbIdentityType identity = {0}; + // In some scenarios(e.g. owner lock), corresponding witness doesn't exist + if (seal.size > 0) { + err = parse_witness_lock(&witness_lock, &seal); + CHECK(err); + } - err = parse_witness_lock(&witness_lock); - CHECK(err); - - err = parse_args(&args); - CHECK(err); + const ArgsType *args = (const ArgsType *)env->script_specific_data; - if (args.has_omni_root) { + if (args->has_omni_root) { if (witness_lock.has_identity) { identity = witness_lock.id; } else { - identity = args.id; + identity = args->id; } } else { - identity = args.id; + identity = args->id; } // regulation compliance, also as administrators if (witness_lock.has_identity) { - CHECK2(args.has_omni_root, ERROR_INVALID_MOL_FORMAT); + CHECK2(args->has_omni_root, ERROR_INVALID_MOL_FORMAT); CHECK2(witness_lock.has_proofs, ERROR_INVALID_MOL_FORMAT); RceState rce_state; rce_init_state(&rce_state); rce_state.rcrules_in_input_cell = true; - err = rce_gather_rcrules_recursively(&rce_state, args.omni_root, 0); + err = rce_gather_rcrules_recursively(&rce_state, args->omni_root, 0); CHECK(err); CHECK2(rce_state.rcrules_count > 0, ERROR_NO_OMNIRULE); CHECK2(rce_state.has_wl, ERROR_NO_WHITE_LIST); @@ -430,29 +338,83 @@ int main() { CHECK(err); } else { // time lock is not used for administrators - if (args.has_since) { - err = check_since(args.since); + if (args->has_since) { + err = check_since(args->since); CHECK(err); } - if (args.has_supply) { - err = check_supply(args.info_cell); + if (args->has_supply) { + err = check_supply(args->info_cell); CHECK(err); } // ACP without signature is not used for administrators - if (args.has_acp && !witness_lock.has_signature) { + if (args->has_acp && !witness_lock.has_signature) { uint64_t min_ckb_amount = 0; uint128_t min_udt_amount = 0; - process_amount(args.ckb_minimum, args.udt_minimum, &min_ckb_amount, + process_amount(args->ckb_minimum, args->udt_minimum, &min_ckb_amount, &min_udt_amount); // skip checking identity to follow ACP return check_payment_unlock(min_ckb_amount, min_udt_amount); } } - ckb_identity_init_code_buffer(code_buff, MAX_CODE_SIZE); + ckb_identity_init_code_buffer(g_code_buff, MAX_CODE_SIZE); err = ckb_verify_identity(&identity, witness_lock.signature, witness_lock.signature_size, witness_lock.preimage, - witness_lock.preimage_size); + witness_lock.preimage_size, smh); CHECK(err); exit: return err; } + +#ifdef CKB_USE_SIM +int simulator_main() { +#else +int main() { +#endif + int err = 0; + Env env; + err = ckb_env_initialize(&env); + CHECK(err); + ArgsType args = {0}; + err = parse_args(env.current_script, &args); + CHECK(err); + env.script_specific_data = &args; + + bool cobuild_activated = false; + err = ckb_cobuild_entry(&env, omnilock_entry, &cobuild_activated); + CHECK(err); + printf("cobuild_activated = %d", cobuild_activated); + if (!cobuild_activated) { + uint8_t witness_source[DEFAULT_DATA_SOURCE_LENGTH]; + mol2_cursor_t lock = {0}; + { + mol2_cursor_t witness_cursor; + err = ckb_new_witness_cursor(&witness_cursor, witness_source, + MAX_CACHE_SIZE, 0, CKB_SOURCE_GROUP_INPUT); + // when witness is missing, empty or not accessible, make it zero length. + // don't fail, because owner lock without omni doesn't require witness. + // when it's zero length, any further actions on witness will fail. + if (err == 0) { + if (witness_cursor.size > 0) { + WitnessArgsType witness_args = make_WitnessArgs(&witness_cursor); + CHECK2(!verify_WitnessArgs(&witness_args), + ERROR_INVALID_WITNESS_FORMAT); + + BytesOptType lock_opt = witness_args.t->lock(&witness_args); + if (lock_opt.t->is_some(&lock_opt)) { + lock = lock_opt.t->unwrap(&lock_opt); + } + } + } + } + + uint8_t smh[BLAKE2B_BLOCK_SIZE] = {0}; + if (lock.size > 0) { + err = generate_sighash_all(smh, BLAKE2B_BLOCK_SIZE); + CHECK(err); + } + err = omnilock_entry(&env, smh, lock); + CHECK(err); + } +exit: + return err; +} diff --git a/c/omni_lock_supply.h b/c/omni_lock_supply.h index 0fc61bc..ccdc1b4 100644 --- a/c/omni_lock_supply.h +++ b/c/omni_lock_supply.h @@ -124,7 +124,7 @@ int compare_cells_data(size_t input_index, size_t output_index) { } -int iterate_by_type_script_hash(uint8_t* hash, size_t source, iterate_func_t func, SupplyContextType* ctx) { +int iterate_by_type_script_hash(const uint8_t* hash, size_t source, iterate_func_t func, SupplyContextType* ctx) { int err = 0; size_t i = 0; uint8_t hash2[32] = {0}; @@ -152,7 +152,7 @@ int iterate_by_type_script_hash(uint8_t* hash, size_t source, iterate_func_t fun return err; } -int check_supply(uint8_t* cell_id) { +int check_supply(const uint8_t* cell_id) { int err = 0; SupplyContextType ctx = {0}; // locate the input info cell diff --git a/c/omni_lock_time_lock.h b/c/omni_lock_time_lock.h index de9df57..357f83e 100644 --- a/c/omni_lock_time_lock.h +++ b/c/omni_lock_time_lock.h @@ -1,73 +1,18 @@ #ifndef OMNI_LOCK_TIME_LOCK_H_ #define OMNI_LOCK_TIME_LOCK_H_ -#define ERROR_INCORRECT_SINCE_FLAGS -23 -#define ERROR_INCORRECT_SINCE_VALUE -24 -/* since */ -#define SINCE_VALUE_BITS 56 -#define SINCE_VALUE_MASK 0x00ffffffffffffff -#define SINCE_EPOCH_FRACTION_FLAG 0b00100000 - -/* a and b are since value, - return 0 if a is equals to b, - return -1 if a is less than b, - return 1 if a is greater than b */ -int epoch_number_with_fraction_cmp(uint64_t a, uint64_t b) { - static const size_t NUMBER_OFFSET = 0; - static const size_t NUMBER_BITS = 24; - static const uint64_t NUMBER_MAXIMUM_VALUE = (1 << NUMBER_BITS); - static const uint64_t NUMBER_MASK = (NUMBER_MAXIMUM_VALUE - 1); - static const size_t INDEX_OFFSET = NUMBER_BITS; - static const size_t INDEX_BITS = 16; - static const uint64_t INDEX_MAXIMUM_VALUE = (1 << INDEX_BITS); - static const uint64_t INDEX_MASK = (INDEX_MAXIMUM_VALUE - 1); - static const size_t LENGTH_OFFSET = NUMBER_BITS + INDEX_BITS; - static const size_t LENGTH_BITS = 16; - static const uint64_t LENGTH_MAXIMUM_VALUE = (1 << LENGTH_BITS); - static const uint64_t LENGTH_MASK = (LENGTH_MAXIMUM_VALUE - 1); - - /* extract a epoch */ - uint64_t a_epoch = (a >> NUMBER_OFFSET) & NUMBER_MASK; - uint64_t a_index = (a >> INDEX_OFFSET) & INDEX_MASK; - uint64_t a_len = (a >> LENGTH_OFFSET) & LENGTH_MASK; - - /* extract b epoch */ - uint64_t b_epoch = (b >> NUMBER_OFFSET) & NUMBER_MASK; - uint64_t b_index = (b >> INDEX_OFFSET) & INDEX_MASK; - uint64_t b_len = (b >> LENGTH_OFFSET) & LENGTH_MASK; - - if (a_epoch < b_epoch) { - return -1; - } else if (a_epoch > b_epoch) { - return 1; - } else { - /* a and b is in the same epoch, - compare a_index / a_len <=> b_index / b_len - */ - uint64_t a_block = a_index * b_len; - uint64_t b_block = b_index * a_len; - /* compare block */ - if (a_block < b_block) { - return -1; - } else if (a_block > b_block) { - return 1; - } else { - return 0; - } - } -} +#include "ckb_utils.h" +#define ERROR_INCORRECT_SINCE_FLAGS (-23) +#define ERROR_INCORRECT_SINCE_VALUE (-24) /* check since, for all inputs the since field must have the exactly same flags with the since constraint, and the value of since must greater or equals than the since - contstaint */ + constraint */ int check_since(uint64_t since) { size_t i = 0; uint64_t len = 0; uint64_t input_since; - /* the 8 msb is flag */ - uint8_t since_flags = since >> SINCE_VALUE_BITS; - uint64_t since_value = since & SINCE_VALUE_MASK; int ret; while (1) { len = sizeof(uint64_t); @@ -80,17 +25,12 @@ int check_since(uint64_t since) { if (ret != CKB_SUCCESS || len != sizeof(uint64_t)) { return ERROR_SYSCALL; } - uint8_t input_since_flags = input_since >> SINCE_VALUE_BITS; - uint64_t input_since_value = input_since & SINCE_VALUE_MASK; - if (since_flags != input_since_flags) { + int comparable = 1; + int cmp = ckb_since_cmp(since, input_since, &comparable); + if (!comparable) { return ERROR_INCORRECT_SINCE_FLAGS; } - if (input_since_flags == SINCE_EPOCH_FRACTION_FLAG) { - ret = epoch_number_with_fraction_cmp(input_since_value, since_value); - if (ret < 0) { - return ERROR_INCORRECT_SINCE_VALUE; - } - } else if (input_since_value < since_value) { + if (cmp == 1) { return ERROR_INCORRECT_SINCE_VALUE; } i += 1; diff --git a/c/rce.h b/c/rce.h index 7a0980c..46f0d2e 100644 --- a/c/rce.h +++ b/c/rce.h @@ -46,6 +46,7 @@ enum ErrorCode { #define CHECK2(cond, code) \ do { \ if (!(cond)) { \ + printf("error at %s:%d, error code %d", __FILE__, __LINE__, code); \ err = code; \ ASSERT(0); \ goto exit; \ @@ -56,6 +57,7 @@ enum ErrorCode { do { \ int code = (_code); \ if (code != 0) { \ + printf("error at %s:%d, error code %d", __FILE__, __LINE__, code); \ err = code; \ ASSERT(0); \ goto exit; \ diff --git a/c/secp256k1_helper.h b/c/secp256k1_helper.h index 0f858ce..ae562a8 100644 --- a/c/secp256k1_helper.h +++ b/c/secp256k1_helper.h @@ -33,40 +33,7 @@ void secp256k1_default_error_callback_fn(const char* str, void* data) { * data should at least be CKB_SECP256K1_DATA_SIZE big * so as to hold all loaded data. */ -int ckb_secp256k1_custom_verify_only_initialize(secp256k1_context* context, - void* data) { - size_t index = 0; - int running = 1; - while (running && index < SIZE_MAX) { - uint64_t len = 32; - uint8_t hash[32]; - - int ret = ckb_load_cell_by_field(hash, &len, 0, index, CKB_SOURCE_CELL_DEP, - CKB_CELL_FIELD_DATA_HASH); - switch (ret) { - case CKB_ITEM_MISSING: - break; - case CKB_SUCCESS: - if (memcmp(ckb_secp256k1_data_hash, hash, 32) == 0) { - /* Found a match, load data here */ - len = CKB_SECP256K1_DATA_SIZE; - ret = ckb_load_cell_data(data, &len, 0, index, CKB_SOURCE_CELL_DEP); - if (ret != CKB_SUCCESS || len != CKB_SECP256K1_DATA_SIZE) { - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } - running = 0; - } - break; - default: - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } - if (running) { - index++; - } - } - if (index == SIZE_MAX) { - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } +int ckb_secp256k1_custom_verify_only_initialize(secp256k1_context* context) { context->illegal_callback = default_illegal_callback; context->error_callback = default_error_callback; @@ -75,7 +42,7 @@ int ckb_secp256k1_custom_verify_only_initialize(secp256k1_context* context, secp256k1_ecmult_gen_context_init(&context->ecmult_gen_ctx); /* Recasting data to (uint8_t*) for pointer math */ - uint8_t* p = data; + uint8_t* p = ckb_secp256k1_data; secp256k1_ge_storage(*pre_g)[] = (secp256k1_ge_storage(*)[])p; secp256k1_ge_storage(*pre_g_128)[] = (secp256k1_ge_storage(*)[])(&p[CKB_SECP256K1_DATA_PRE_SIZE]); diff --git a/c/secp256k1_helper_20210801.h b/c/secp256k1_helper_20210801.h deleted file mode 100644 index 3b1e9f4..0000000 --- a/c/secp256k1_helper_20210801.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef CKB_SECP256K1_HELPER_H_ -#define CKB_SECP256K1_HELPER_H_ - -#include "ckb_syscalls.h" -#include "secp256k1_data_info_20210801.h" - -#define CKB_SECP256K1_HELPER_ERROR_LOADING_DATA -101 -#define CKB_SECP256K1_HELPER_ERROR_ILLEGAL_CALLBACK -102 -#define CKB_SECP256K1_HELPER_ERROR_ERROR_CALLBACK -103 - -/* - * We are including secp256k1 implementation directly so gcc can strip - * unused functions. For some unknown reasons, if we link in libsecp256k1.a - * directly, the final binary will include all functions rather than those used. - */ -#define HAVE_CONFIG_H 1 -#define USE_EXTERNAL_DEFAULT_CALLBACKS -#include - -void secp256k1_default_illegal_callback_fn(const char* str, void* data) { - (void)str; - (void)data; - ckb_exit(CKB_SECP256K1_HELPER_ERROR_ILLEGAL_CALLBACK); -} - -void secp256k1_default_error_callback_fn(const char* str, void* data) { - (void)str; - (void)data; - ckb_exit(CKB_SECP256K1_HELPER_ERROR_ERROR_CALLBACK); -} - -/* - * data should at least be CKB_SECP256K1_DATA_SIZE big - * so as to hold all loaded data. - */ -int ckb_secp256k1_custom_verify_only_initialize(secp256k1_context* context, - void* data) { - size_t index = 0; - int running = 1; - while (running && index < SIZE_MAX) { - uint64_t len = 32; - uint8_t hash[32]; - - int ret = ckb_load_cell_by_field(hash, &len, 0, index, CKB_SOURCE_CELL_DEP, - CKB_CELL_FIELD_DATA_HASH); - switch (ret) { - case CKB_ITEM_MISSING: - break; - case CKB_SUCCESS: - if (memcmp(ckb_secp256k1_data_hash, hash, 32) == 0) { - /* Found a match, load data here */ - len = CKB_SECP256K1_DATA_SIZE; - ret = ckb_load_cell_data(data, &len, 0, index, CKB_SOURCE_CELL_DEP); - if (ret != CKB_SUCCESS || len != CKB_SECP256K1_DATA_SIZE) { - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } - running = 0; - } - break; - default: - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } - if (running) { - index++; - } - } - if (index == SIZE_MAX) { - return CKB_SECP256K1_HELPER_ERROR_LOADING_DATA; - } - - context->illegal_callback = default_illegal_callback; - context->error_callback = default_error_callback; - - secp256k1_ecmult_context_init(&context->ecmult_ctx); - secp256k1_ecmult_gen_context_init(&context->ecmult_gen_ctx); - - /* Recasting data to (uint8_t*) for pointer math */ - uint8_t* p = data; - secp256k1_ge_storage(*pre_g)[] = (secp256k1_ge_storage(*)[])p; - secp256k1_ge_storage(*pre_g_128)[] = - (secp256k1_ge_storage(*)[])(&p[CKB_SECP256K1_DATA_PRE_SIZE]); - context->ecmult_ctx.pre_g = pre_g; - context->ecmult_ctx.pre_g_128 = pre_g_128; - - return 0; -} - -#endif diff --git a/c/secp256k1_lock.h b/c/secp256k1_lock.h deleted file mode 100644 index 83f6caf..0000000 --- a/c/secp256k1_lock.h +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef CKB_LOCK_UTILS_H_ -#define CKB_LOCK_UTILS_H_ - -#define BLAKE2B_BLOCK_SIZE 32 -#define BLAKE160_SIZE 20 -#define PUBKEY_SIZE 33 -#define TEMP_SIZE 32768 -#define RECID_INDEX 64 -/* 32 KB */ -#define MAX_WITNESS_SIZE 32768 -#define SCRIPT_SIZE 32768 -#define SIGNATURE_SIZE 65 - -/* secp256k1 unlock errors */ -#define ERROR_ARGUMENTS_LEN -1 -#define ERROR_ENCODING -2 -#define ERROR_SYSCALL -3 -#define ERROR_SECP_RECOVER_PUBKEY -11 -#define ERROR_SECP_VERIFICATION -12 -#define ERROR_SECP_PARSE_PUBKEY -13 -#define ERROR_SECP_PARSE_SIGNATURE -14 -#define ERROR_SECP_SERIALIZE_PUBKEY -15 -#define ERROR_SCRIPT_TOO_LONG -21 -#define ERROR_WITNESS_SIZE -22 -#define ERROR_INCORRECT_SINCE_FLAGS -23 -#define ERROR_INCORRECT_SINCE_VALUE -24 -#define ERROR_PUBKEY_BLAKE160_HASH -31 - -#if (MAX_WITNESS_SIZE > TEMP_SIZE) || (SCRIPT_SIZE > TEMP_SIZE) -#error "Temp buffer is not big enough!" -#endif - -/* Extract lock from WitnessArgs */ -int extract_witness_lock(uint8_t *witness, uint64_t len, - mol_seg_t *lock_bytes_seg) { - mol_seg_t witness_seg; - witness_seg.ptr = witness; - witness_seg.size = len; - - if (MolReader_WitnessArgs_verify(&witness_seg, false) != MOL_OK) { - return ERROR_ENCODING; - } - mol_seg_t lock_seg = MolReader_WitnessArgs_get_lock(&witness_seg); - - if (MolReader_BytesOpt_is_none(&lock_seg)) { - return ERROR_ENCODING; - } - *lock_bytes_seg = MolReader_Bytes_raw_bytes(&lock_seg); - return CKB_SUCCESS; -} - -/* - * Load secp256k1 first witness and check the signature - * - * This function return CKB_SUCCESS if the witness is a valid WitnessArgs - * and the length of WitnessArgs#lock field is exactly the SIGNATURE_SIZE - * - * Arguments: - * * witness bytes, a buffer to receive the first witness bytes of the input - * cell group - * * witness len, a pointer to receive the first witness length - * - * Witness: - * WitnessArgs with a signature in lock field used to present ownership. - */ -int load_secp256k1_first_witness_and_check_signature( - unsigned char witness_bytes[MAX_WITNESS_SIZE], uint64_t *witness_len) { - int ret; - /* Load witness of first input */ - *witness_len = MAX_WITNESS_SIZE; - ret = ckb_load_witness(witness_bytes, witness_len, 0, 0, - CKB_SOURCE_GROUP_INPUT); - if (ret != CKB_SUCCESS) { - return ERROR_SYSCALL; - } - - if (*witness_len > MAX_WITNESS_SIZE) { - return ERROR_WITNESS_SIZE; - } - - /* load signature */ - mol_seg_t witness_lock_seg; - ret = extract_witness_lock(witness_bytes, *witness_len, &witness_lock_seg); - if (ret != 0) { - return ERROR_ENCODING; - } - - if (witness_lock_seg.size != SIGNATURE_SIZE) { - return ERROR_ARGUMENTS_LEN; - } - return CKB_SUCCESS; -} - -/* - * Arguments: - * * pubkey blake160 hash, blake2b hash of pubkey first 20 bytes, used to - * shield the real pubkey. - * * first witness bytes, the first witness bytes of the input cell group - * * first witness len, length of first witness bytes - */ -int verify_secp256k1_blake160_sighash_all_with_witness( - unsigned char pubkey_hash[BLAKE160_SIZE], - unsigned char first_witness_bytes[MAX_WITNESS_SIZE], - uint64_t first_witness_len) { - int ret; - unsigned char temp[MAX_WITNESS_SIZE]; - unsigned char lock_bytes[SIGNATURE_SIZE]; - - /* copy first witness to temp, we keep the first_witness_bytes untouched in - * this function */ - uint64_t len = first_witness_len; - memcpy(temp, first_witness_bytes, len); - - /* load signature */ - mol_seg_t lock_bytes_seg; - ret = extract_witness_lock(temp, first_witness_len, &lock_bytes_seg); - if (ret != 0) { - return ERROR_ENCODING; - } - - if (lock_bytes_seg.size != SIGNATURE_SIZE) { - return ERROR_ARGUMENTS_LEN; - } - memcpy(lock_bytes, lock_bytes_seg.ptr, lock_bytes_seg.size); - - /* Load tx hash */ - unsigned char tx_hash[BLAKE2B_BLOCK_SIZE]; - len = BLAKE2B_BLOCK_SIZE; - ret = ckb_load_tx_hash(tx_hash, &len, 0); - if (ret != CKB_SUCCESS) { - return ret; - } - if (len != BLAKE2B_BLOCK_SIZE) { - return ERROR_SYSCALL; - } - - /* Prepare sign message */ - unsigned char message[BLAKE2B_BLOCK_SIZE]; - blake2b_state blake2b_ctx; - blake2b_init(&blake2b_ctx, BLAKE2B_BLOCK_SIZE); - blake2b_update(&blake2b_ctx, tx_hash, BLAKE2B_BLOCK_SIZE); - - /* Clear lock field to zero, then digest the first witness */ - memset((void *)lock_bytes_seg.ptr, 0, lock_bytes_seg.size); - blake2b_update(&blake2b_ctx, (char *)&first_witness_len, sizeof(uint64_t)); - blake2b_update(&blake2b_ctx, temp, first_witness_len); - - /* Digest same group witnesses */ - size_t i = 1; - while (1) { - len = MAX_WITNESS_SIZE; - ret = ckb_load_witness(temp, &len, 0, i, CKB_SOURCE_GROUP_INPUT); - if (ret == CKB_INDEX_OUT_OF_BOUND) { - break; - } - if (ret != CKB_SUCCESS) { - return ERROR_SYSCALL; - } - if (len > MAX_WITNESS_SIZE) { - return ERROR_WITNESS_SIZE; - } - blake2b_update(&blake2b_ctx, (char *)&len, sizeof(uint64_t)); - blake2b_update(&blake2b_ctx, temp, len); - i += 1; - } - /* Digest witnesses that not covered by inputs */ - i = ckb_calculate_inputs_len(); - while (1) { - len = MAX_WITNESS_SIZE; - ret = ckb_load_witness(temp, &len, 0, i, CKB_SOURCE_INPUT); - if (ret == CKB_INDEX_OUT_OF_BOUND) { - break; - } - if (ret != CKB_SUCCESS) { - return ERROR_SYSCALL; - } - if (len > MAX_WITNESS_SIZE) { - return ERROR_WITNESS_SIZE; - } - blake2b_update(&blake2b_ctx, (char *)&len, sizeof(uint64_t)); - blake2b_update(&blake2b_ctx, temp, len); - i += 1; - } - blake2b_final(&blake2b_ctx, message, BLAKE2B_BLOCK_SIZE); - - /* Load signature */ - secp256k1_context context; - uint8_t secp_data[CKB_SECP256K1_DATA_SIZE]; - ret = ckb_secp256k1_custom_verify_only_initialize(&context, secp_data); - if (ret != 0) { - return ret; - } - - secp256k1_ecdsa_recoverable_signature signature; - if (secp256k1_ecdsa_recoverable_signature_parse_compact( - &context, &signature, lock_bytes, lock_bytes[RECID_INDEX]) == 0) { - return ERROR_SECP_PARSE_SIGNATURE; - } - - /* Recover pubkey */ - secp256k1_pubkey pubkey; - if (secp256k1_ecdsa_recover(&context, &pubkey, &signature, message) != 1) { - return ERROR_SECP_RECOVER_PUBKEY; - } - - /* Check pubkey hash */ - size_t pubkey_size = PUBKEY_SIZE; - if (secp256k1_ec_pubkey_serialize(&context, temp, &pubkey_size, &pubkey, - SECP256K1_EC_COMPRESSED) != 1) { - return ERROR_SECP_SERIALIZE_PUBKEY; - } - - blake2b_init(&blake2b_ctx, BLAKE2B_BLOCK_SIZE); - blake2b_update(&blake2b_ctx, temp, pubkey_size); - blake2b_final(&blake2b_ctx, temp, BLAKE2B_BLOCK_SIZE); - - if (memcmp(pubkey_hash, temp, BLAKE160_SIZE) != 0) { - return ERROR_PUBKEY_BLAKE160_HASH; - } - - return 0; -} - -#endif /* CKB_LOCK_UTILS_H_ */ diff --git a/c/top_level.mol b/c/top_level.mol new file mode 100644 index 0000000..7ab2ad3 --- /dev/null +++ b/c/top_level.mol @@ -0,0 +1,8 @@ +import basic; + +union WitnessLayout { + SighashAll: 4278190081, + SighashAllOnly: 4278190082, + Otx: 4278190083, + OtxStart: 4278190084, +} diff --git a/deps/ckb-c-stdlib b/deps/ckb-c-stdlib new file mode 160000 index 0000000..61c7819 --- /dev/null +++ b/deps/ckb-c-stdlib @@ -0,0 +1 @@ +Subproject commit 61c7819c9ccf164f5e13d8439c554f80857e2c4b diff --git a/deps/ckb-c-stdlib-20210801 b/deps/ckb-c-stdlib-20210801 deleted file mode 160000 index 20578df..0000000 --- a/deps/ckb-c-stdlib-20210801 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 20578dfb092b3b3761df755395e20ec142a83d6e diff --git a/deps/ed25519 b/deps/ed25519 new file mode 160000 index 0000000..34582a3 --- /dev/null +++ b/deps/ed25519 @@ -0,0 +1 @@ +Subproject commit 34582a3340312ca1ce8eeccb0b1eb1ced548bd3c diff --git a/deps/secp256k1-20210801 b/deps/secp256k1 similarity index 100% rename from deps/secp256k1-20210801 rename to deps/secp256k1 diff --git a/test-vectors/README.md b/test-vectors/README.md new file mode 100644 index 0000000..582d494 --- /dev/null +++ b/test-vectors/README.md @@ -0,0 +1,3 @@ + +These test vectors require [ckb-debugger](https://github.com/nervosnetwork/ckb-standalone-debugger.git) installed. +Use shell script `run-all.sh` to run all scripts. diff --git a/test-vectors/run-all.sh b/test-vectors/run-all.sh new file mode 100644 index 0000000..6cfc90d --- /dev/null +++ b/test-vectors/run-all.sh @@ -0,0 +1,9 @@ +#!/bin/bash +for file in *.json; do + echo $file + ckb-debugger --bin ../build/omni_lock -f $file -i 0 -s lock + if (($? != 0)); then + exit 1 + fi +done + diff --git a/test-vectors/tx_btc_P2PKH_compressed.json b/test-vectors/tx_btc_P2PKH_compressed.json new file mode 100644 index 0000000..ad6a44b --- /dev/null +++ b/test-vectors/tx_btc_P2PKH_compressed.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0xdea9fe01c9ac44bf67e256ddbda8aa38cceab479d5e9a258d082c6f947dfe976", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x04fe5ee37ff7962f1661615c1f7b57d728e15e5e1d00" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0xe6b26aebbec9c2b0eb56a0908ec4d8d1c18ad8b85479e3e2040de5cb4ed09c79", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x8a7362467938fbc5dfc0db411190d84ac0ba5484840c210fe9def994136da4b9", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x570f24c51006d012a49edca8224600fc40acb1de65e0845d4637bbb817a44f9a", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0xe6b26aebbec9c2b0eb56a0908ec4d8d1c18ad8b85479e3e2040de5cb4ed09c79", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x8a7362467938fbc5dfc0db411190d84ac0ba5484840c210fe9def994136da4b9", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x570f24c51006d012a49edca8224600fc40acb1de65e0845d4637bbb817a44f9a", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0xdea9fe01c9ac44bf67e256ddbda8aa38cceab479d5e9a258d082c6f947dfe976", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d00000055000000550000001000000055000000550000004100000020f7d2be56af39715ad504b8efee1d452b51c374e6403b8a26e71f761814c84fa94ab7cfe84fa8a3d681e7bc88908654c707f13ddcdc25fd69982501ffd8c57ce920000000cd750bd601b71570de98e60a0d29f25cb4952e474357f6f4e562ee11b465f6b0" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_btc_P2PKH_uncompressed.json b/test-vectors/tx_btc_P2PKH_uncompressed.json new file mode 100644 index 0000000..80ebf64 --- /dev/null +++ b/test-vectors/tx_btc_P2PKH_uncompressed.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0x05046fcd76a480b41e19f809e4d07a0357e1ced3584351bcf0e73df7c555da4e", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x0481ed18ea9760cbce2e1d08df6e902a246a94d01e00" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0x4bffda352ef79c5cc6f642544977a4d09ee06d5e5e48f151a7b0a29523e4deac", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa0b74c6aab7a2e4f4b17780c3aebae9f77394ad7e61b035864443f02c82acf10", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xf658c925dbb6667639b1a2fddf838390fb3a0756ec87a12b9e31cd9c104207f0", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0x4bffda352ef79c5cc6f642544977a4d09ee06d5e5e48f151a7b0a29523e4deac", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa0b74c6aab7a2e4f4b17780c3aebae9f77394ad7e61b035864443f02c82acf10", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xf658c925dbb6667639b1a2fddf838390fb3a0756ec87a12b9e31cd9c104207f0", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0x05046fcd76a480b41e19f809e4d07a0357e1ced3584351bcf0e73df7c555da4e", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d0000005500000055000000100000005500000055000000410000001babece9ad42f96159eadd0d85e9fc7270181b0b53bf18844546e0483e1e4d69e63de00f348e662988c2b9747c05e7eb1d3f680c08cbf0eee6aeeae78f5926356420000000fbce361e03e3a60d3cda33a704b3b705663454e3e9c012647378cfe029ed6464" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_btc_Segwit_Bech32.json b/test-vectors/tx_btc_Segwit_Bech32.json new file mode 100644 index 0000000..7329676 --- /dev/null +++ b/test-vectors/tx_btc_Segwit_Bech32.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0x128ffc9f7bb137088f3731864810925d6833e26477a7f36363f5e55f58b7776c", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x04b19c301d73f66c5e9ec886d91e0832cde8f778ce00" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa8433dac5579b99ae428cee6fab72092fc19367bb2be79d0dc517de41f7462e2", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x31eccfa8eb39b832a0d906fc78ebaa10011d19f22ea7091ba5309feb25616cdd", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xeed77a312e4a4331b9f372007aa129b6f2803f01d99116437652e058302100a4", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0xa8433dac5579b99ae428cee6fab72092fc19367bb2be79d0dc517de41f7462e2", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x31eccfa8eb39b832a0d906fc78ebaa10011d19f22ea7091ba5309feb25616cdd", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xeed77a312e4a4331b9f372007aa129b6f2803f01d99116437652e058302100a4", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0x128ffc9f7bb137088f3731864810925d6833e26477a7f36363f5e55f58b7776c", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d000000550000005500000010000000550000005500000041000000289b023f11132b0cede5c301eae6cd557b0232202a9ed55d0ea3531eada142645144fbdbecf36ea866c3a5e64ec85ab41d4c7dc72689ec727bc56fb165aee6af102000000048a3ddad43f843536592c8dd5715f20d6a01bf008be315cc8a0f63bca84be408" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_btc_Segwit_P2SH.json b/test-vectors/tx_btc_Segwit_P2SH.json new file mode 100644 index 0000000..44450eb --- /dev/null +++ b/test-vectors/tx_btc_Segwit_P2SH.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0xee4f5ba9dd3a9d240ca144ac1db631ad5c0859f953c1f46acd2eab27330d485d", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x046939b8ddba1008fa4b5152f4d7ab9542d15df92900" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0xeab2ed467d69b80d4fa948b6806408d13e37cc115df2d9e9af3e858c719e8671", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x80fbb790af25fd12cd4c0350d9f2d09912106c66f1a2b25e66dad05257dbc9ef", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x66793107b02105606fee1f99e9f9d37fbbbba11410235ceea54764e31d1f8615", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0xeab2ed467d69b80d4fa948b6806408d13e37cc115df2d9e9af3e858c719e8671", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x80fbb790af25fd12cd4c0350d9f2d09912106c66f1a2b25e66dad05257dbc9ef", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x66793107b02105606fee1f99e9f9d37fbbbba11410235ceea54764e31d1f8615", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0xee4f5ba9dd3a9d240ca144ac1db631ad5c0859f953c1f46acd2eab27330d485d", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d00000055000000550000001000000055000000550000004100000023618f3520abbe36565e31c63ceb47a3e107259810c97e75c67e385672e47174af619f9fca4a889123bf39e82ba045984bc43e6b04a9e752964af495dab9f27f48200000002da4f277a82d8311315e40995252ec6445240004e3105262ad6bd9a62ea31c83" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_cobuild_btc_compressed.json b/test-vectors/tx_cobuild_btc_compressed.json new file mode 100644 index 0000000..3dd8e92 --- /dev/null +++ b/test-vectors/tx_cobuild_btc_compressed.json @@ -0,0 +1,147 @@ +{ + "mock_info": { + "cell_deps": [ + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x146b17fff1c01825cd3197f4bcf862c171510e1d9505f51e902301a0337619e7" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0xb6d48c1c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x088d6fea298bc2f464f141a6f129dd91e61496b318ad364080ceed140be5dddf" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x1093d9c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null, + "output": { + "capacity": "0x11510", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x0000000000000000000000000000000000000000000000000000000000000000", + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type" + } + } + } + ], + "extensions": [], + "header_deps": [], + "inputs": [ + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x0", + "tx_hash": "0xaa6f2a459a8c962baab66ebf67cc35d8fdecee22b5be130d5fb62ada8b3fdf54" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x2a", + "lock": { + "args": "0x0470781b76897c0edd4aa5057bea9a73ea185a3b2000", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + } + ] + }, + "tx": { + "cell_deps": [ + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x146b17fff1c01825cd3197f4bcf862c171510e1d9505f51e902301a0337619e7" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x088d6fea298bc2f464f141a6f129dd91e61496b318ad364080ceed140be5dddf" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + } + ], + "header_deps": [], + "inputs": [ + { + "previous_output": { + "index": "0x0", + "tx_hash": "0xaa6f2a459a8c962baab66ebf67cc35d8fdecee22b5be130d5fb62ada8b3fdf54" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "version": "0x0", + "witnesses": [ + "0x010000ff720000000c000000180000000c00000008000000040000005600000000550000001000000055000000550000004100000020da699152a6b45d3aac5cd80e23ae808563e91f34edeb8daba6ab2cca6e872ff646401ce75f83f14a427ee23136fdab775a181d485c87ef41677558778a0dd449" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_cobuild_eth.json b/test-vectors/tx_cobuild_eth.json new file mode 100644 index 0000000..50cde5b --- /dev/null +++ b/test-vectors/tx_cobuild_eth.json @@ -0,0 +1,147 @@ +{ + "mock_info": { + "cell_deps": [ + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xba5efb9ac041b8a9903714229dd1cbde752b1acf06f175e2d90b7c98062b05e8" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0xb6d48c1c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x93ecea87c27c63047e3a46ce3949a48fdc7543370e94607b79a98bc1ee102211" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x1093d9c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null, + "output": { + "capacity": "0x11510", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x0000000000000000000000000000000000000000000000000000000000000000", + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type" + } + } + } + ], + "extensions": [], + "header_deps": [], + "inputs": [ + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x0", + "tx_hash": "0xf0a13aa6ba92a6c7964e9d56f3d58e1bed7733915a11e5632ede9ac4b555be9f" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x2a", + "lock": { + "args": "0x01ad61ecc6a18fa3bffba0302904cdb75cab985e8300", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + } + ] + }, + "tx": { + "cell_deps": [ + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xba5efb9ac041b8a9903714229dd1cbde752b1acf06f175e2d90b7c98062b05e8" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x93ecea87c27c63047e3a46ce3949a48fdc7543370e94607b79a98bc1ee102211" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + } + ], + "header_deps": [], + "inputs": [ + { + "previous_output": { + "index": "0x0", + "tx_hash": "0xf0a13aa6ba92a6c7964e9d56f3d58e1bed7733915a11e5632ede9ac4b555be9f" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "version": "0x0", + "witnesses": [ + "0x010000ff720000000c000000180000000c0000000800000004000000560000000055000000100000005500000055000000410000004339230594966d4b858026e5211d9e89aadbf18a7245cf60771352ed0a4050874adacb4cb7214550eda37ec67d6dc4932518dbd6c17cff6c7c8bd921d87ee80601" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_cobuild_otx_multiple.json b/test-vectors/tx_cobuild_otx_multiple.json new file mode 100644 index 0000000..1400952 --- /dev/null +++ b/test-vectors/tx_cobuild_otx_multiple.json @@ -0,0 +1,279 @@ +{ + "mock_info": { + "cell_deps": [ + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x1", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x3", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x4", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + } + ], + "extensions": [], + "header_deps": [ + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + }, + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + }, + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x1515151515151515151515151515151515151515151515151515151515151515", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + }, + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x1616161616161616161616161616161616161616161616161616161616161616", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + } + ], + "inputs": [ + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x2", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x04751e76e8199196d454941c45d1b3a323f1433bd600", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + }, + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x5", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x012b5ad5c4795c026514f8317c7a215e218dccd6cf00", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + } + ] + }, + "tx": { + "cell_deps": [ + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x1", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x3", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x4", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + ], + "header_deps": [ + "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "0x1515151515151515151515151515151515151515151515151515151515151515", + "0x1616161616161616161616161616161616161616161616161616161616161616" + ], + "inputs": [ + { + "previous_output": { + "index": "0x2", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + }, + { + "previous_output": { + "index": "0x5", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + } + }, + { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + } + } + ], + "outputs_data": [ + "0x", + "0x" + ], + "version": "0x0", + "witnesses": [ + "0x040000ff2400000014000000180000001c0000002000000000000000000000000000000000000000", + "0x030000ff9e0100001c0000002000000024000000280000002c0000001001000001000000010000000200000002000000e400000008000000dc00000008000000d40000001000000030000000500000000000000000000000000000000000000000000000000000000000000000000000c95ece04afa1b145418965a8d714229e5d8f90abae50d729e33150de82cadaef8000000042424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242428e00000008000000860000000c0000002c00000026886143059c5cee1bf44bb1a899b6dc06c32c6a0dda31e0d13adb413f53a32b56000000005500000010000000550000005500000041000000203b598c4e7e669491a97c8b8f80a32f8b3d3a18428b75bb86632ddc613e876d2c673adda3d8cf8dfa50d8eb75a3466cdaa46a99c3bb0ae52080a1f78836facb89", + "0x030000ff9e0100001c0000002000000024000000280000002c0000001001000001000000010000000200000002000000e400000008000000dc00000008000000d40000001000000030000000500000000000000000000000000000000000000000000000000000000000000000000000c95ece04afa1b145418965a8d714229e5d8f90abae50d729e33150de82cadaef8000000042424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242428e00000008000000860000000c0000002c0000006f24a75d882144f4b1dfdec15d78f91ad652ea1566080f1f57ec0be055e532cb5600000000550000001000000055000000550000004100000063c2b19970f061f29d014a298bcb6a4cc766d935fe61ded05e1d6c8ae779730d04aef806263c44ef385f8a6c51849b186083aee6a0a96015ee503c0c0775b75f01" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_cobuild_otx_simple.json b/test-vectors/tx_cobuild_otx_simple.json new file mode 100644 index 0000000..e172a30 --- /dev/null +++ b/test-vectors/tx_cobuild_otx_simple.json @@ -0,0 +1,153 @@ +{ + "mock_info": { + "cell_deps": [ + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x1", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + } + ], + "extensions": [], + "header_deps": [ + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + }, + { + "compact_target": "0x20800000", + "dao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "epoch": "0x0", + "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "nonce": "0x0", + "number": "0x0", + "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0", + "transactions_root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0" + } + ], + "inputs": [ + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x2", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x0", + "lock": { + "args": "0x04751e76e8199196d454941c45d1b3a323f1433bd600", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + } + ] + }, + "tx": { + "cell_deps": [ + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x1", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + ], + "header_deps": [ + "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c" + ], + "inputs": [ + { + "previous_output": { + "index": "0x2", + "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x0", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + } + } + ], + "outputs_data": [ + "0x" + ], + "version": "0x0", + "witnesses": [ + "0x040000ff2400000014000000180000001c0000002000000000000000000000000000000000000000", + "0x030000ff9e0100001c0000002000000024000000280000002c0000001001000001000000010000000200000002000000e400000008000000dc00000008000000d40000001000000030000000500000000000000000000000000000000000000000000000000000000000000000000000c95ece04afa1b145418965a8d714229e5d8f90abae50d729e33150de82cadaef8000000042424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242428e00000008000000860000000c0000002c00000026886143059c5cee1bf44bb1a899b6dc06c32c6a0dda31e0d13adb413f53a32b56000000005500000010000000550000005500000041000000203b598c4e7e669491a97c8b8f80a32f8b3d3a18428b75bb86632ddc613e876d2c673adda3d8cf8dfa50d8eb75a3466cdaa46a99c3bb0ae52080a1f78836facb89" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_cobuild_sighash_all_only.json b/test-vectors/tx_cobuild_sighash_all_only.json new file mode 100644 index 0000000..2c6238d --- /dev/null +++ b/test-vectors/tx_cobuild_sighash_all_only.json @@ -0,0 +1,147 @@ +{ + "mock_info": { + "cell_deps": [ + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xda6eff4ae31af68e7b6cef74954e2bbb3cd492b8b775c796c0e710bb606410c9" + } + }, + "data": "0x{{ data ../build/omni_lock }}", + "header": null, + "output": { + "capacity": "0xb6d48c1c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x19b35bd168e6f34d993950b3258331fcd7b038e3db89ce81e14f9ca48c9ff170" + } + }, + "data": "0x{{ data ../build/always_success }}", + "header": null, + "output": { + "capacity": "0x1093d9c800", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + }, + { + "cell_dep": { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null, + "output": { + "capacity": "0x11510", + "lock": { + "args": "0x", + "code_hash": "0x60fc4b3cfd4ca5977d0749238f1301e99929b5665bb8eb9160227e7b41b48ccb", + "hash_type": "data1" + }, + "type": { + "args": "0x0000000000000000000000000000000000000000000000000000000000000000", + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type" + } + } + } + ], + "extensions": [], + "header_deps": [], + "inputs": [ + { + "data": "0x", + "header": null, + "input": { + "previous_output": { + "index": "0x0", + "tx_hash": "0x0a07b06fc33bee94e6537fc9373007bc1280cc7e3904169f4d6237933f176dae" + }, + "since": "0x0" + }, + "output": { + "capacity": "0x2a", + "lock": { + "args": "0x0470a77f210b815b48af715e424639e14dae70939700", + "code_hash": "0xce6b8f2ba48b3ed6d84a851daad2c0bd28a084c6c31a6943a3f39cbb4d48df10", + "hash_type": "data1" + }, + "type": null + } + } + ] + }, + "tx": { + "cell_deps": [ + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xda6eff4ae31af68e7b6cef74954e2bbb3cd492b8b775c796c0e710bb606410c9" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0x19b35bd168e6f34d993950b3258331fcd7b038e3db89ce81e14f9ca48c9ff170" + } + }, + { + "dep_type": "code", + "out_point": { + "index": "0x0", + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066" + } + } + ], + "header_deps": [], + "inputs": [ + { + "previous_output": { + "index": "0x0", + "tx_hash": "0x0a07b06fc33bee94e6537fc9373007bc1280cc7e3904169f4d6237933f176dae" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "args": "0x", + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "version": "0x0", + "witnesses": [ + "0x020000ff620000000800000056000000005500000010000000550000005500000041000000202ff48ddf895ce2d8786d0af5f68d21f90705534dbc453c891272cee1a6650a004f755326ad2a9336181139923cea1fc0ddc7cd1180e92c571f41f9f4ed05ed9d" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_eth.json b/test-vectors/tx_eth.json new file mode 100644 index 0000000..2c8149b --- /dev/null +++ b/test-vectors/tx_eth.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0x44e6de084ee13cf884f71864fdb3aafb4398a87ae6b0345b7f1d77bb44bca7b0", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x01840cb79096ecbed6ebbdb181f89825da5a73566200" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0xd79fc373c88056e9cd1865613bb0a2cda756dabbc65234b4ef8ee7ad3c011657", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x8173219326f1b748840631d7535ffd54b1c8d605a3b045f8db3583f9601ca8f3", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x41b38d4d1a6c93f6da1b0106ff590a31bbdb5dec539f486984f8305c4c047c64", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0xd79fc373c88056e9cd1865613bb0a2cda756dabbc65234b4ef8ee7ad3c011657", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x8173219326f1b748840631d7535ffd54b1c8d605a3b045f8db3583f9601ca8f3", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x41b38d4d1a6c93f6da1b0106ff590a31bbdb5dec539f486984f8305c4c047c64", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0x44e6de084ee13cf884f71864fdb3aafb4398a87ae6b0345b7f1d77bb44bca7b0", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d000000550000005500000010000000550000005500000041000000fbe1e03e98c37cd1e7135b7b072696463a8bab5ae1dc5ae84710b5c5f6cf4410131fa2bc5e70df768e14f3555c53064b0416cda285f6b675e139ea6ae36593ab012000000051cd14e79750652e9fbb84ec65dcabe8b6b40a66902fdd9f9d0a763019c82c82" + ] + } +} \ No newline at end of file diff --git a/test-vectors/tx_eth_displaying.json b/test-vectors/tx_eth_displaying.json new file mode 100644 index 0000000..fc83e85 --- /dev/null +++ b/test-vectors/tx_eth_displaying.json @@ -0,0 +1,174 @@ +{ + "mock_info": { + "inputs": [ + { + "input": { + "since": "0x0", + "previous_output": { + "tx_hash": "0x84757cec14a387aa66dc3ceb22659e9ebc7713be555061a303930ce34495cffc", + "index": "0x0" + } + }, + "output": { + "capacity": "0x2a", + "lock": { + "code_hash": "0x519b7adaa5a4b585d15aa14fe605d55b2e71235b8c4868784a3553d4d034a929", + "hash_type": "data", + "args": "0x122d5b9c9de18c04b74515dc0a709b2087d88cbde000" + }, + "type": null + }, + "data": "0x", + "header": null + } + ], + "cell_deps": [ + { + "cell_dep": { + "out_point": { + "tx_hash": "0x3b12c8cf1699a49f4a9404d073e5fe777ccbaae32157103007a145dd1dcc231a", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xb627b19f800", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xc46c5af6c53bf4cb63c437092c68ca5d937b5e612b253e0ad0c901500509e71a", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0xbebc20000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/always_success }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0x338744a588ad05210c671c619e42a4a8679409696786feb870f32bc731f51320", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x5f5e10000000", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + }, + "data": "0x{{ data ../build/secp256k1_data }}", + "header": null + }, + { + "cell_dep": { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + }, + "output": { + "capacity": "0x11510", + "lock": { + "code_hash": "0xd483925160e4232b2cb29f012e8380b7b612d71cf4e79991476b6bcf610735f6", + "hash_type": "data", + "args": "0x" + }, + "type": { + "code_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "hash_type": "type", + "args": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "data": "0x{{ data ../build/validate_signature_rsa }}", + "header": null + } + ], + "header_deps": [], + "extensions": [] + }, + "tx": { + "version": "0x0", + "cell_deps": [ + { + "out_point": { + "tx_hash": "0x3b12c8cf1699a49f4a9404d073e5fe777ccbaae32157103007a145dd1dcc231a", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xc46c5af6c53bf4cb63c437092c68ca5d937b5e612b253e0ad0c901500509e71a", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0x338744a588ad05210c671c619e42a4a8679409696786feb870f32bc731f51320", + "index": "0x0" + }, + "dep_type": "code" + }, + { + "out_point": { + "tx_hash": "0xa638f65f650bdac13bf91134ed7eec8feded1dac5e6add9e26cf658b2a693066", + "index": "0x0" + }, + "dep_type": "code" + } + ], + "header_deps": [], + "inputs": [ + { + "since": "0x0", + "previous_output": { + "tx_hash": "0x84757cec14a387aa66dc3ceb22659e9ebc7713be555061a303930ce34495cffc", + "index": "0x0" + } + } + ], + "outputs": [ + { + "capacity": "0x2a", + "lock": { + "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash_type": "data", + "args": "0x" + }, + "type": null + } + ], + "outputs_data": [ + "0x" + ], + "witnesses": [ + "0x8d00000010000000690000008d000000550000005500000010000000550000005500000041000000722f2d6b6ccefaec16a754fbdc2cae8390ab8e3a4f54cf24ecfd95663c96a27027865a7d8ee2b96bda3dea2670fea821aac5dae8e7cf6c345366b98ce94c7cfa00200000007d5c4db4aad6fd65329c1b812fabfb8ffe8a31a0db22109ae54489a4a41dd713" + ] + } +} \ No newline at end of file diff --git a/tests/omni_lock/CMakeLists.txt b/tests/omni_lock/CMakeLists.txt index 12b1630..03d6206 100644 --- a/tests/omni_lock/CMakeLists.txt +++ b/tests/omni_lock/CMakeLists.txt @@ -18,17 +18,17 @@ add_definitions(-DCKB_USE_SIM) add_definitions(-DSECP256K1_BUILD) include_directories(../../tests/omni_lock) -include_directories(../../deps/ckb-c-stdlib-20210801) +include_directories(../../deps/ckb-c-stdlib) include_directories(../../deps/sparse-merkle-tree/c) # include_directories(deps/ckb-c-stdlib/libc) # on simulator, we don't use own "libc" -include_directories(../../deps/secp256k1-20210801/src) -include_directories(../../deps/secp256k1-20210801) -include_directories(../../deps/ckb-c-stdlib-20210801/molecule) +include_directories(../../deps/secp256k1/src) +include_directories(../../deps/secp256k1) +include_directories(../../deps/ckb-c-stdlib/molecule) include_directories(../../c) include_directories(../../build) add_executable(omni_lock_simulator ../../tests/omni_lock/omni_lock_sim.c) target_compile_definitions(omni_lock_simulator PUBLIC -D_FILE_OFFSET_BITS=64 -DCKB_DECLARATION_ONLY) -target_include_directories(omni_lock_simulator PUBLIC deps/ckb-c-stdlib-20210801/libc) +target_include_directories(omni_lock_simulator PUBLIC deps/ckb-c-stdlib/libc) target_link_libraries(omni_lock_simulator dl) diff --git a/tests/omni_lock/ckb_syscall_omni_lock_sim.h b/tests/omni_lock/ckb_syscall_omni_lock_sim.h index b5313db..dd46164 100644 --- a/tests/omni_lock/ckb_syscall_omni_lock_sim.h +++ b/tests/omni_lock/ckb_syscall_omni_lock_sim.h @@ -22,6 +22,7 @@ mol_seg_t build_bytes(const uint8_t* data, uint32_t len); mol_seg_t build_script(const uint8_t* code_hash, uint8_t hash_type, const uint8_t* args, uint32_t args_len); +int ckb_load_transaction(void* addr, uint64_t* len, size_t offset); int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset); int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, size_t source); @@ -85,8 +86,6 @@ typedef struct RcLockSettingType { // test scheme bool wrong_signature; bool wrong_pubkey_hash; - // owner lock without rc doesn't require witness - bool empty_witness; } RcLockSettingType; RcLockSettingType g_setting = {0}; @@ -109,6 +108,7 @@ typedef struct RcLockStates { uint32_t witness_count; slice_t script; + slice_t transaction; slice_t cell_data[64]; uint32_t cell_data_count; @@ -366,6 +366,26 @@ void convert_setting_to_states(void) { // make witness again, with correct signature convert_witness(); + // Build a dummy transaction that is just enough for omnilock + { + mol_builder_t witness_builder; + MolBuilder_BytesVec_init(&witness_builder); + mol_seg_t witness = + build_bytes(g_states.witness[0].ptr, g_states.witness[0].size); + MolBuilder_BytesVec_push(&witness_builder, witness.ptr, witness.size); + mol_seg_res_t witness_res = MolBuilder_BytesVec_build(witness_builder); + free(witness.ptr); + + mol_builder_t tx_builder; + MolBuilder_Transaction_init(&tx_builder); + MolBuilder_Transaction_set_witnesses(&tx_builder, witness_res.seg.ptr, + witness_res.seg.size); + mol_seg_res_t tx_res = MolBuilder_Transaction_build(tx_builder); + + g_states.transaction.ptr = tx_res.seg.ptr; + g_states.transaction.size = tx_res.seg.size; + } + // Script uint8_t script_args[1 + 20 + 1 + 32 + 2 + 8] = {0}; uint32_t script_args_len = 22; @@ -549,12 +569,29 @@ int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, return CKB_INDEX_OUT_OF_BOUND; } - if (g_setting.empty_witness) { + slice_t seg = g_states.witness[0]; + + if (addr == NULL) { + *len = seg.size; + return 0; + } + if (seg.size <= offset) { *len = 0; return 0; } + uint32_t remaining = seg.size - offset; + if (remaining > *len) { + memcpy(addr, seg.ptr + offset, *len); + } else { + memcpy(addr, seg.ptr + offset, remaining); + } + *len = remaining; - slice_t seg = g_states.witness[0]; + return 0; +} + +int ckb_load_transaction(void* addr, uint64_t* len, size_t offset) { + slice_t seg = g_states.transaction; if (addr == NULL) { *len = seg.size; @@ -664,7 +701,7 @@ int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, size_t source) { if (source == CKB_SOURCE_CELL_DEP && index == SPECIAL_SECP256K1_INDEX) { ASSERT(*len == 1048576); - FILE* input = fopen("build/secp256k1_data_20210801", "rb"); + FILE* input = fopen("build/secp256k1_data", "rb"); size_t read_item = fread(addr, *len, 1, input); ASSERT(read_item == 1); @@ -904,6 +941,11 @@ int ckb_exec_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset, return 0; } +int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, + size_t source) { + return -1; +} + #undef ASSERT #define ASSERT(s) (void)0 diff --git a/tests/omni_lock/exec_fuzzer/Makefile b/tests/omni_lock/exec_fuzzer/Makefile index cba0089..756291c 100644 --- a/tests/omni_lock/exec_fuzzer/Makefile +++ b/tests/omni_lock/exec_fuzzer/Makefile @@ -16,16 +16,16 @@ LLVM_COV=llvm-cov CORPUS_DIR=corpus -FUZZER_FLAGS=-g -O1 -fsanitize=fuzzer,address,undefined -fsanitize-recover=address -I ../../../c -I ../../../deps/ckb-c-stdlib-20210801 +FUZZER_FLAGS=-g -O1 -fsanitize=fuzzer,address,undefined -fsanitize-recover=address -I ../../../c -I ../../../deps/ckb-c-stdlib COVERAGE_DIR=coverage -COVERAGE_FLAGS=-fprofile-instr-generate -fcoverage-mapping -I ../../../c -I ../../../deps/ckb-c-stdlib-20210801 +COVERAGE_FLAGS=-fprofile-instr-generate -fcoverage-mapping -I ../../../c -I ../../../deps/ckb-c-stdlib ifeq ($(OS),MacOS) COVERAGE_FLAGS+=-Wl,-U,_LLVMFuzzerCustomMutator -Wl,-U,_LLVMFuzzerInitialize endif -EXTERNAL_HEADERS=../../../deps/ckb-c-stdlib-20210801/ckb_exec.h +EXTERNAL_HEADERS=../../../deps/ckb-c-stdlib/ckb_exec.h all: fuzzer coverage diff --git a/tests/omni_lock/omni_lock_sim.c b/tests/omni_lock/omni_lock_sim.c index 42c9770..c6a5162 100644 --- a/tests/omni_lock/omni_lock_sim.c +++ b/tests/omni_lock/omni_lock_sim.c @@ -3,6 +3,7 @@ #else #define ASSERT(s) (void)0 #endif +#include int ckb_exit(signed char code); @@ -37,6 +38,11 @@ int hex2bin(uint8_t* buf, const char* src) { return length; } +int ed25519_verify(const unsigned char* signature, const unsigned char* message, + size_t message_len, const unsigned char* public_key) { + return 0; +} + UTEST(pubkey_hash, pass) { init_input(&g_setting); g_setting.flags = IdentityFlagsCkb; @@ -52,7 +58,6 @@ UTEST(pubkey_hash, wrong_signature) { g_setting.wrong_signature = true; convert_setting_to_states(); - int r = simulator_main(); bool b = (r == ERROR_IDENTITY_PUBKEY_BLAKE160_HASH || r == ERROR_IDENTITY_SECP_RECOVER_PUBKEY || @@ -90,26 +95,6 @@ UTEST(owner_lock, pass) { ASSERT_EQ(0, r); } -UTEST(owner_lock_without_witness, pass) { - init_input(&g_setting); - g_setting.flags = IdentityFlagsOwnerLock; - g_setting.empty_witness = true; - - uint8_t blake160[20] = {0xBE, 0xEF}; - - g_setting.input_lsh[0] = new_slice(32); - memcpy(g_setting.input_lsh[0].ptr, blake160, sizeof(blake160)); - g_setting.input_lsh[0].size = 32; - - g_setting.input_lsh_count = 1; - memcpy(g_setting.blake160, blake160, sizeof(blake160)); - - convert_setting_to_states(); - - int r = simulator_main(); - ASSERT_EQ(0, r); -} - UTEST(owner_lock, not_pass) { init_input(&g_setting); g_setting.flags = IdentityFlagsOwnerLock; diff --git a/tests/omni_lock_rust/Cargo.lock b/tests/omni_lock_rust/Cargo.lock index 00d109c..3cae86c 100644 --- a/tests/omni_lock_rust/Cargo.lock +++ b/tests/omni_lock_rust/Cargo.lock @@ -3,19 +3,19 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] [[package]] -name = "aho-corasick" -version = "0.6.10" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" -dependencies = [ - "memchr 2.7.1", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "anyhow" @@ -38,11 +38,38 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bit-vec" -version = "0.5.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" @@ -58,9 +85,9 @@ checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "blake2b-ref" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95916998c798756098a4eb1b3f2cd510659705a9817bf203d61abd30fbec3e7b" +checksum = "294d17c72e0ba59fad763caa112368d0672083779cdebbb97164f4bb4c1e339a" [[package]] name = "blake2b-rs" @@ -71,6 +98,16 @@ dependencies = [ "cc", ] +[[package]] +name = "blake2b-rs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89a8565807f21b913288968e391819e7f9b2f0f46c7b89549c051cccf3a2771" +dependencies = [ + "cc", + "cty", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -96,6 +133,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -111,6 +157,33 @@ dependencies = [ "serde", ] +[[package]] +name = "cacache" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142316461ed3a3dfcba10417317472da5bfd0461e4d276bf7c07b330766d9490" +dependencies = [ + "digest 0.10.7", + "either", + "futures", + "hex", + "libc", + "memmap2", + "miette", + "reflink-copy", + "serde", + "serde_derive", + "serde_json", + "sha1", + "sha2", + "ssri", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "walkdir", +] + [[package]] name = "cc" version = "1.0.83" @@ -134,16 +207,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ckb-chain-spec" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6545c270115cdbed0b5ec452a4ef8753dac8990ac0996110531041a00f0842f9" +checksum = "210df338c83691c2173136656c411c3fe09578a66377a05014956419bede76cf" dependencies = [ + "cacache", "ckb-constant", "ckb-crypto", "ckb-dao-utils", "ckb-error", "ckb-hash", "ckb-jsonrpc-types", + "ckb-logger", "ckb-pow", "ckb-rational", "ckb-resource", @@ -155,24 +230,24 @@ dependencies = [ [[package]] name = "ckb-channel" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0048e1732dc769525b332a20a4eb0942f84e1ba3cbcbcb286dacd3a585f6e50a" +checksum = "50d21e6d4ad47858609ced9d887e63e821ba6770f28e7be58e8d56213a0d0924" dependencies = [ "crossbeam-channel", ] [[package]] name = "ckb-constant" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237ea9a8e7ced2731a46bbbf23b40a7df4c5229bb2226396ba70bfe4cdc85e3c" +checksum = "b42093e370876b71569292fc0aa9ae1078114ee678c4e4b4ae77a81b590fdba7" [[package]] name = "ckb-crypto" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c69f679e843fae7294679efdbe6239aaf9469a40f0b3145e075708879b26513" +checksum = "35ed640e73c39b5e0fc8a39c6d013733761023424e2bc70dafd74d92ce6c36cb" dependencies = [ "ckb-fixed-hash", "faster-hex 0.6.1", @@ -184,9 +259,9 @@ dependencies = [ [[package]] name = "ckb-dao-utils" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915bbb801dee8f14e47714b18b8c8216c574156c7a1bd922fba2f73d73a8f10a" +checksum = "aaf9300f9b1ff36e576ca6ed374ec9704f6da6f61492ea48038ff0b9067c2779" dependencies = [ "byteorder", "ckb-error", @@ -195,9 +270,9 @@ dependencies = [ [[package]] name = "ckb-error" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945d804f5648bd3060b0d19336952093f3bbc6cc568533230156d5f579fef24c" +checksum = "9948a60c3fa47131ec9907cfb64c94e4fd9199ef9329ba0ba4d53b8e03adfbbe" dependencies = [ "anyhow", "ckb-occupied-capacity", @@ -207,9 +282,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e74fcc7ab5e6274991cdd7b3a49583b45f63c1d82cda639edd259d7cf73bd2" +checksum = "0629983e05127c5bbf025cefdac36a91c3a0720acf1b2e2637ff1f0ac673a78c" dependencies = [ "ckb-fixed-hash-core", "ckb-fixed-hash-macros", @@ -217,9 +292,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-core" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b845d71fee1b55f68453c8db69b54a43db1370147f0f79909324eaf030a28e2e" +checksum = "c582d7d52e96ce65c2995a7f399c6dc3f314fec64dd15d47ec903896ac24a428" dependencies = [ "faster-hex 0.6.1", "serde", @@ -228,31 +303,46 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-macros" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff13f0f845ae9fb1073239094e6cadaf7af213181e7462df4f73cdb81d6b5ee6" +checksum = "3bae4184f70cbd2e36839d902f403f06ea6a009df67ac2f7d37942890459618c" dependencies = [ "ckb-fixed-hash-core", "proc-macro2", - "quote 1.0.35", + "quote", "syn 1.0.109", ] +[[package]] +name = "ckb-gen-types" +version = "0.113.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c709b63557041d03db0bc09b56ddc95de455ea555d537d5599117163f095973c" +dependencies = [ + "cfg-if 1.0.0", + "ckb-error", + "ckb-fixed-hash", + "ckb-hash", + "ckb-occupied-capacity", + "molecule", + "numext-fixed-uint", +] + [[package]] name = "ckb-hash" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f409236f9c815cebf15dea49924bf3f316d47682f710fa9493135993a57d7913" +checksum = "b78504239eedf043013a4c1d5a3cf38a2917ef37643c3608ff4183aa2888f48f" dependencies = [ "blake2b-ref", - "blake2b-rs", + "blake2b-rs 0.2.0", ] [[package]] name = "ckb-jsonrpc-types" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b11f78288ab8f299caf7b316706ca41d8b7a67a5e20719245d584230dce003" +checksum = "97cf7e01a18fb980f3d993fafdf06999379b71ebca098196ed42824bab0b3d9d" dependencies = [ "ckb-types", "faster-hex 0.6.1", @@ -262,18 +352,27 @@ dependencies = [ [[package]] name = "ckb-logger" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14feffc8b90fd0e5dead8b8c0609faf5e6b5f3c06ceb487b8f0c91f378dc92cf" +checksum = "e3f5f89647d0d71aef57cafc580c8ca770b1e7afa85400c29de10c6d6a5d2adc" dependencies = [ - "log 0.4.20", + "log", +] + +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] name = "ckb-occupied-capacity" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a42877e9e929241d9965b8fa0337c3dc93715c452df0c305f4a6cceda4ecdda" +checksum = "bfe678c0047869c71ae01369ada83ebb43567504c3c5e338a64dcd679b98ecad" dependencies = [ "ckb-occupied-capacity-core", "ckb-occupied-capacity-macros", @@ -281,43 +380,43 @@ dependencies = [ [[package]] name = "ckb-occupied-capacity-core" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80447a92eeef022f9dff53413d46900cbab5a8e28bd5ef49c88512a3b8aa5d6d" +checksum = "35dba70fddc9eda1906875b4c99b14d64910a429a58972658e8f65930f77f27b" dependencies = [ "serde", ] [[package]] name = "ckb-occupied-capacity-macros" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab646c39f21c297ce0fd274bfe27361830adf2d64d0f15b2ef320dea2001cb5" +checksum = "1a37efa3314fc8d1b6ead861743e7012126204449a7c6579f0e571a3456d0d34" dependencies = [ "ckb-occupied-capacity-core", - "quote 1.0.35", + "quote", "syn 1.0.109", ] [[package]] name = "ckb-pow" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b034068b7746d5cc666c95fcdaf355bd9c302f3d68207e9c6e988e7307c8ad" +checksum = "c28156a3ea6941bad362f0de75a2358bc759f52d505b4cfae0db223e25646fdd" dependencies = [ "byteorder", "ckb-hash", "ckb-types", "eaglesong", - "log 0.4.20", + "log", "serde", ] [[package]] name = "ckb-rational" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80648e2f04b2429c96497dfd786edbbaabcde45d3f566ef96bb84c6fe1c3999c" +checksum = "a0d64ef7e9b0785e1b2acdc1a96072bbdefa6ac72bca36de91d9d9e65cd39bbd" dependencies = [ "numext-fixed-uint", "serde", @@ -325,9 +424,9 @@ dependencies = [ [[package]] name = "ckb-resource" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21111aa1eaf33e998163bdc35bb01a22cb5a71660a8c694dbaaa7455668807e1" +checksum = "ea0c9ca6ccc86e4ed3f49c3dc05b1bd58f27205cb9ded891b86995a9edd06974" dependencies = [ "ckb-system-scripts", "ckb-types", @@ -335,15 +434,14 @@ dependencies = [ "includedir_codegen", "phf", "serde", - "tempfile", "walkdir", ] [[package]] name = "ckb-script" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86c9aa8b59733bbf92195d9596a24e369db27614593b522582ab24e2436c255c" +checksum = "ec56fceeff7d1fb5229bf03af876360dabf7f9da7eab67a3ce5164c09b4a90d4" dependencies = [ "byteorder", "ckb-chain-spec", @@ -353,19 +451,17 @@ dependencies = [ "ckb-traits", "ckb-types", "ckb-vm", - "ckb-vm-definitions", "faster-hex 0.6.1", - "goblin 0.2.3", "serde", ] [[package]] name = "ckb-system-scripts" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfbce46ad2de7563c7e456888d4a29df3d461106a989836c08627d044409e928" +checksum = "fa5c59063142de7a68cfad4449c6b3863563856219a2925dfb8c5f019ec2aa47" dependencies = [ - "blake2b-rs", + "blake2b-rs 0.2.0", "faster-hex 0.6.1", "includedir", "includedir_codegen", @@ -374,40 +470,44 @@ dependencies = [ [[package]] name = "ckb-traits" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8629d61183ab240fe0c598b5723c16bc9741691df2261574ff04c6fb87cb070d" +checksum = "a4fe215ac785af5f9011aeae14f6f1b05d8cad7ca76a98fe97bf374650e07ccc" dependencies = [ "ckb-types", ] [[package]] name = "ckb-types" -version = "0.100.0-rc2" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31588d3154ce8e3bd7d815b6e8223afecbcf3ca05a58a26db371393eb0ffe42a" +checksum = "eb8a1e28eeb4bc18dfc0e97306147d1c9399ffab6292185346a2af2983ed80f3" dependencies = [ "bit-vec", - "bitflags 1.3.2", "bytes", "ckb-channel", + "ckb-constant", "ckb-error", "ckb-fixed-hash", + "ckb-gen-types", "ckb-hash", + "ckb-merkle-mountain-range", "ckb-occupied-capacity", "ckb-rational", "derive_more", + "golomb-coded-set", "merkle-cbt", "molecule", "numext-fixed-uint", "once_cell", + "paste", ] [[package]] name = "ckb-vm" -version = "0.20.0-rc2" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3edaa6828e414b2d8cf773acaa561fd104ac595028de9326df790a1f7ba40f8" +checksum = "0cc004a826b9bc9319ffae0b8415690e1b5f1482266d55fbd43843aa40ddcd63" dependencies = [ "byteorder", "bytes", @@ -416,33 +516,19 @@ dependencies = [ "derive_more", "goblin 0.2.3", "goblin 0.4.0", - "libc", - "mapr", "rand 0.7.3", "scroll", "serde", ] -[[package]] -name = "ckb-vm-debug-utils" -version = "0.1.0" -source = "git+https://github.com/nervosnetwork/ckb-vm-debug-utils.git?rev=f72995f#f72995fc02f665aef356c81c3e0d5030fdac88c2" -dependencies = [ - "byteorder", - "bytes", - "ckb-vm", - "env_logger", - "gdb-remote-protocol", - "libc", - "log 0.4.20", - "nix", -] - [[package]] name = "ckb-vm-definitions" -version = "0.20.1" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45af9be584526f91e1517739802d0ebf82eb8d14853c45128ce930144a171ddd" +checksum = "c4ced3ff9d79b53d93c106720f6c1f855694290e33581850e05c859500eee83f" +dependencies = [ + "paste", +] [[package]] name = "cloudabi" @@ -453,6 +539,12 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "convert_case" version = "0.4.0" @@ -479,22 +571,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.3.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.6.6" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -dependencies = [ - "cfg-if 0.1.10", - "lazy_static", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -506,6 +594,50 @@ dependencies = [ "typenum", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -514,7 +646,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", "proc-macro2", - "quote 1.0.35", + "quote", "rustc_version", "syn 1.0.109", ] @@ -545,20 +677,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d978bd5d343e8ab9b5c0fc8d93ff9c602fdc96616ffff9c05ac7a155419b824" [[package]] -name = "env_logger" -version = "0.4.3" +name = "ed25519" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "log 0.3.9", - "regex", + "pkcs8", + "signature", ] [[package]] -name = "faster-hex" -version = "0.3.1" +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b8cccaafb5aae8c282692e5590f341925edea6c696e8715ff0d973320b2646" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] [[package]] name = "faster-hex" @@ -566,6 +722,27 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" +[[package]] +name = "faster-hex" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" +dependencies = [ + "serde", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fiat-crypto" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + [[package]] name = "flate2" version = "1.0.28" @@ -598,14 +775,92 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "gdb-remote-protocol" -version = "0.1.0" -source = "git+https://github.com/luser/rust-gdb-remote-protocol?rev=565ab0c#565ab0c0ac189c82b0e7df217860599fc1ae6287" +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ - "log 0.4.20", - "nom", - "strum", - "strum_macros", + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", ] [[package]] @@ -626,16 +881,33 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "goblin" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" dependencies = [ - "log 0.4.20", + "log", "plain", "scroll", ] @@ -646,11 +918,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "532a09cd3df2c6bbfc795fb0434bff8f22255d1d07328180e918a2e6ce122d4d" dependencies = [ - "log 0.4.20", + "log", "plain", "scroll", ] +[[package]] +name = "golomb-coded-set" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7076c0cd6257d84b785b0f22c36443dd47a5e86a1256d7ef82c8cb88ea9a7e" +dependencies = [ + "siphasher", +] + [[package]] name = "heapsize" version = "0.4.2" @@ -668,9 +949,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "includedir" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97402f770a519ebea51b27131c3b6558cfd2375aff21294bad806bad91bf0b6" +checksum = "afd126bd778c00c43a9dc76d1609a0894bf4222088088b2217ccc0ce9e816db7" dependencies = [ "flate2", "phf", @@ -678,9 +959,9 @@ dependencies = [ [[package]] name = "includedir_codegen" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7d542be113fd84855692fb536c16cc4c09527724d1dca8953047d71cccadef" +checksum = "0ac1500c9780957c9808c4ec3b94002f35aab01483833f5a8bce7dfb243e3148" dependencies = [ "flate2", "phf_codegen", @@ -715,13 +996,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] -name = "log" -version = "0.3.9" +name = "linux-raw-sys" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.20", -] +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" @@ -730,30 +1008,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] -name = "mapr" -version = "0.8.0" +name = "memchr" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a28a55dbc005b2f6f123c4058933d57add373d362f6fd3a76aab4fe6973500" -dependencies = [ - "libc", - "winapi", -] +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] -name = "memchr" -version = "1.0.2" +name = "memmap2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - [[package]] name = "merkle-cbt" version = "0.3.2" @@ -764,45 +1032,46 @@ dependencies = [ ] [[package]] -name = "miniz_oxide" -version = "0.7.1" +name = "miette" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ - "adler", + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", ] [[package]] -name = "molecule" -version = "0.7.1" +name = "miette-derive" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58d1147f4d0d51ce72c56a6099ae5dbfd007b250271bb965f82dd10fca2bf02" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ - "bytes", - "cfg-if 1.0.0", - "faster-hex 0.6.1", + "proc-macro2", + "quote", + "syn 2.0.48", ] [[package]] -name = "nix" -version = "0.15.0" +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if 0.1.10", - "libc", - "void", + "adler", ] [[package]] -name = "nom" -version = "3.2.1" +name = "molecule" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +checksum = "d4fd9767ab5e5f2ea40f71ff4c8bdb633c50509052e093c2fdd0e390a749dfa3" dependencies = [ - "memchr 1.0.2", + "bytes", + "cfg-if 1.0.0", + "faster-hex 0.6.1", ] [[package]] @@ -812,7 +1081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "621fe0f044729f810c6815cdd77e8f5e0cd803ce4f6a38380ebfc1322af98661" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -847,32 +1116,45 @@ checksum = "0200f8d55c36ec1b6a8cf810115be85d4814f045e0097dfd50033ba25adb4c9e" dependencies = [ "numext-fixed-uint-core", "proc-macro2", - "quote 1.0.35", + "quote", "syn 1.0.109", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "omni-lock-test" version = "0.1.0" dependencies = [ - "blake2b-rs", + "blake2b-ref", + "blake2b-rs 0.1.5", + "bs58", "ckb-chain-spec", "ckb-crypto", "ckb-error", "ckb-hash", + "ckb-jsonrpc-types", "ckb-script", "ckb-traits", "ckb-types", "ckb-vm", - "ckb-vm-debug-utils", - "faster-hex 0.3.1", - "gdb-remote-protocol", + "ed25519-dalek", + "faster-hex 0.9.0", "hex", - "includedir_codegen", "lazy_static", + "molecule", "openssl", "rand 0.6.5", "ripemd", + "serde", + "serde_json", "sha2", "sha3", "sparse-merkle-tree", @@ -912,7 +1194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "syn 2.0.48", ] @@ -928,20 +1210,26 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "phf" -version = "0.7.24" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.7.24" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" dependencies = [ "phf_generator", "phf_shared", @@ -949,23 +1237,45 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.7.24" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" dependencies = [ "phf_shared", - "rand 0.6.5", + "rand 0.7.3", ] [[package]] name = "phf_shared" -version = "0.7.24" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.28" @@ -978,6 +1288,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -993,12 +1309,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" - [[package]] name = "quote" version = "1.0.35" @@ -1033,7 +1343,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.16", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -1082,7 +1392,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.12", ] [[package]] @@ -1176,39 +1495,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "regex" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -dependencies = [ - "aho-corasick", - "memchr 2.7.1", - "regex-syntax", - "thread_local", - "utf8-ranges", -] - -[[package]] -name = "regex-syntax" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "ucd-util", + "bitflags 1.3.2", ] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "reflink-copy" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "767be24c0da52e7448d495b8d162506a9aa125426651d547d545d6c2b4b65b62" dependencies = [ - "winapi", + "cfg-if 1.0.0", + "rustix", + "windows", ] [[package]] @@ -1220,6 +1522,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1229,6 +1537,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.16" @@ -1260,24 +1581,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "syn 1.0.109", ] [[package]] name = "secp256k1" -version = "0.19.0" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6179428c22c73ac0fbb7b5579a56353ce78ba29759b3b8575183336ea74cdfb" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.3.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11553d210db090930f4432bea123b31f70bbf693ace14504ea2a35e796c28dd2" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" dependencies = [ "cc", ] @@ -1304,7 +1625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "syn 2.0.48", ] @@ -1319,6 +1640,28 @@ dependencies = [ "serde", ] +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1342,47 +1685,71 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "siphasher" -version = "0.2.3" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "sparse-merkle-tree" version = "0.5.2-rc1" source = "git+https://github.com/nervosnetwork/sparse-merkle-tree.git?rev=2dce546#2dce546eab6f7eaaab3a0886247fd12ac798ad28" dependencies = [ - "blake2b-rs", + "blake2b-rs 0.1.5", "cfg-if 0.1.10", ] [[package]] -name = "strum" -version = "0.8.0" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] [[package]] -name = "strum_macros" -version = "0.8.0" +name = "ssri" +version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3384590878eb0cab3b128e844412e2d010821e7e091211b9d87324173ada7db8" +checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" dependencies = [ - "quote 0.3.15", - "syn 0.11.11", + "base64", + "digest 0.10.7", + "hex", + "miette", + "serde", + "sha-1", + "sha2", + "thiserror", + "xxhash-rust", ] [[package]] -name = "syn" -version = "0.11.11" +name = "subtle" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -dependencies = [ - "quote 0.3.15", - "synom", - "unicode-xid", -] +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -1391,7 +1758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "unicode-ident", ] @@ -1402,31 +1769,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "unicode-ident", ] -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -dependencies = [ - "unicode-xid", -] - [[package]] name = "tempfile" -version = "3.1.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ - "cfg-if 0.1.10", - "libc", - "rand 0.7.3", + "cfg-if 1.0.0", + "fastrand", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys", ] [[package]] @@ -1445,17 +1802,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", - "quote 1.0.35", + "quote", "syn 2.0.48", ] [[package]] -name = "thread_local" -version = "0.3.6" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "lazy_static", + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] @@ -1473,12 +1870,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "ucd-util" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -1486,16 +1877,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "unicode-xid" -version = "0.0.4" +name = "unicode-width" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" - -[[package]] -name = "utf8-ranges" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "vcpkg" @@ -1509,12 +1894,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "walkdir" version = "2.4.0" @@ -1531,6 +1910,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" @@ -1561,3 +1946,100 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "xxhash-rust" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53be06678ed9e83edb1745eb72efc0bbcd7b5c3c35711a860906aed827a13d61" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tests/omni_lock_rust/Cargo.toml b/tests/omni_lock_rust/Cargo.toml index 48ca362..6d20c47 100644 --- a/tests/omni_lock_rust/Cargo.toml +++ b/tests/omni_lock_rust/Cargo.toml @@ -8,33 +8,28 @@ edition = "2018" [dependencies] blake2b-rs = "0.1" -ckb-crypto = "0.100.0-rc2" -ckb-error = "0.100.0-rc2" -ckb-hash = "0.100.0-rc2" -ckb-script = "0.100.0-rc2" -ckb-traits = "0.100.0-rc2" -ckb-types = "0.100.0-rc2" -ckb-chain-spec = "0.100.0-rc2" -# ckb-crypto = "0.40.0" -# ckb-error = "0.40.0" -# ckb-hash = "0.40.0" -# ckb-script = "0.40.0" -# ckb-traits = "0.40.0" -# ckb-types = "0.40.0" -# ckb-vm = "=0.19.3" +ckb-crypto = "0.113.0" +ckb-error = "0.113.0" +ckb-hash = "0.113.0" +ckb-script = "0.113.0" +ckb-traits = "0.113.0" +ckb-types = "0.113.0" +ckb-chain-spec = "0.113.0" +ckb-jsonrpc-types = "0.113.0" +ckb-vm = "0.24.6" + lazy_static = "1.3.0" rand = "0.6.5" sparse-merkle-tree = { git = "https://github.com/nervosnetwork/sparse-merkle-tree.git", rev = "2dce546"} openssl = "0.10.4" sha3 = "0.9.1" -ckb-vm-debug-utils = { git = "https://github.com/nervosnetwork/ckb-vm-debug-utils.git", rev = "f72995f" } -gdb-remote-protocol = { git = "https://github.com/luser/rust-gdb-remote-protocol", rev = "565ab0c" } -ckb-vm = { version = "=0.20.0-rc2", features = ["detect-asm"] } ripemd = "0.1.3" sha2 = "0.10.6" hex = "0.4.3" - -[build-dependencies] -includedir_codegen = "0.5.0" -blake2b-rs = "0.1.5" -faster-hex = "0.3" +faster-hex = "0.9.0" +molecule = "0.7.5" +blake2b-ref = "0.3.1" +serde = "1.0" +serde_json = "1.0" +ed25519-dalek = "2.1.1" +bs58 = "0.5.1" diff --git a/tests/omni_lock_rust/build.rs b/tests/omni_lock_rust/build.rs deleted file mode 100644 index b0b2821..0000000 --- a/tests/omni_lock_rust/build.rs +++ /dev/null @@ -1,82 +0,0 @@ -pub use blake2b_rs::{Blake2b, Blake2bBuilder}; -use includedir_codegen::Compression; - -use std::{ - env, - fs::File, - io::{BufWriter, Read, Write}, - path::Path, -}; - -const PATH_PREFIX: &str = "../../build/"; -const BUF_SIZE: usize = 8 * 1024; -const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; - -const BINARIES: &[(&str, &str)] = &[ - ( - "omni_lock", - "768f306681da232ceb0b94f436c5f813377179762a831c5ad8797bd4fd2d118d", - ), -]; - -fn main() { - let mut bundled = includedir_codegen::start("BUNDLED_CELL"); - - let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join("code_hashes.rs"); - let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); - - let mut errors = Vec::new(); - - for (name, expected_hash) in BINARIES { - let path = format!("{}{}", PATH_PREFIX, name); - - let mut buf = [0u8; BUF_SIZE]; - bundled - .add_file(&path, Compression::Gzip) - .expect("add files to resource bundle"); - - // build hash - let mut blake2b = new_blake2b(); - let mut fd = File::open(&path).expect("open file"); - loop { - let read_bytes = fd.read(&mut buf).expect("read file"); - if read_bytes > 0 { - blake2b.update(&buf[..read_bytes]); - } else { - break; - } - } - - let mut hash = [0u8; 32]; - blake2b.finalize(&mut hash); - - let actual_hash = faster_hex::hex_string(&hash).unwrap(); - if expected_hash != &actual_hash { - errors.push((name, expected_hash, actual_hash)); - continue; - } - - write!( - &mut out_file, - "pub const {}: [u8; 32] = {:?};\n", - format!("CODE_HASH_{}", name.to_uppercase()), - hash - ) - .expect("write to code_hashes.rs"); - } - - if !errors.is_empty() { - for (name, expected, actual) in errors.into_iter() { - eprintln!("{}: expect {}, actual {}", name, expected, actual); - } - panic!("not all hashes are right"); - } - - bundled.build("bundled.rs").expect("build resource bundle"); -} - -pub fn new_blake2b() -> Blake2b { - Blake2bBuilder::new(32) - .personal(CKB_HASH_PERSONALIZATION) - .build() -} diff --git a/tests/omni_lock_rust/rust-toolchain b/tests/omni_lock_rust/rust-toolchain index 4934985..883bde3 100644 --- a/tests/omni_lock_rust/rust-toolchain +++ b/tests/omni_lock_rust/rust-toolchain @@ -1 +1 @@ -1.69.0 +1.71.1 \ No newline at end of file diff --git a/tests/omni_lock_rust/rustfmt.toml b/tests/omni_lock_rust/rustfmt.toml new file mode 100644 index 0000000..c775577 --- /dev/null +++ b/tests/omni_lock_rust/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 120 +use_small_heuristics = "Max" diff --git a/tests/omni_lock_rust/src/blake2b.rs b/tests/omni_lock_rust/src/blake2b.rs new file mode 100644 index 0000000..b0c9677 --- /dev/null +++ b/tests/omni_lock_rust/src/blake2b.rs @@ -0,0 +1,20 @@ +pub use blake2b_ref::{Blake2b, Blake2bBuilder}; + +pub const PERSONALIZATION_SIGHASH_ALL: &[u8] = b"ckb-tcob-sighash"; +pub const PERSONALIZATION_SIGHASH_ALL_ONLY: &[u8] = b"ckb-tcob-sgohash"; +pub const PERSONALIZATION_OTX: &[u8] = b"ckb-tcob-otxhash"; + +/// return a blake2b instance with personalization for SighashAll +pub fn new_sighash_all_blake2b() -> Blake2b { + Blake2bBuilder::new(32).personal(PERSONALIZATION_SIGHASH_ALL).build() +} + +/// return a blake2b instance with personalization for SighashAllOnly +pub fn new_sighash_all_only_blake2b() -> Blake2b { + Blake2bBuilder::new(32).personal(PERSONALIZATION_SIGHASH_ALL_ONLY).build() +} + +/// return a blake2b instance with personalization for OTX +pub fn new_otx_blake2b() -> Blake2b { + Blake2bBuilder::new(32).personal(PERSONALIZATION_OTX).build() +} diff --git a/tests/omni_lock_rust/src/debug_utils.rs b/tests/omni_lock_rust/src/debug_utils.rs deleted file mode 100644 index 67844e3..0000000 --- a/tests/omni_lock_rust/src/debug_utils.rs +++ /dev/null @@ -1,75 +0,0 @@ -#![allow(unused_imports)] -#![allow(dead_code)] - -use ckb_script::cost_model::transferred_byte_cycles; -use ckb_script::{ScriptGroup, ScriptGroupType, ScriptVersion, TransactionScriptsVerifier}; -use ckb_traits::{CellDataProvider, HeaderProvider}; -use ckb_types::bytes::Bytes; -use ckb_types::packed::Byte32; -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; -use ckb_vm::{DefaultMachineBuilder, SupportMachine}; -use ckb_vm_debug_utils::{GdbHandler, Stdio}; -use gdb_remote_protocol::process_packets_from; -use std::net::TcpListener; - -/* -* addr: the address listening on, e.g. 127.0.0.1:9999 -* script_group: the script_group (type/lock) to run -* program: bytes of risc-v binary which must contain debug information -* args: arguments passed to script -* verifier: -*/ -pub fn debug<'a, DL: CellDataProvider + HeaderProvider>( - addr: &str, - script_type: ScriptGroupType, - script_hash: Byte32, - program: &Bytes, - args: &[Bytes], - verifier: &TransactionScriptsVerifier<'a, DL>, -) { - let script_group = get_script_group(&verifier, script_type, &script_hash).unwrap(); - - // GDB path - let listener = TcpListener::bind(addr).expect("listen"); - let script_version = ScriptVersion::V1; - let max_cycle = 70_000_000u64; - - for res in listener.incoming() { - if let Ok(stream) = res { - let core_machine = AsmCoreMachine::new( - script_version.vm_isa(), - script_version.vm_version(), - max_cycle, - ); - let builder = DefaultMachineBuilder::new(core_machine) - .instruction_cycle_func(verifier.cost_model()) - .syscall(Box::new(Stdio::new(true))); - let builder = verifier - .generate_syscalls(script_version, script_group) - .into_iter() - .fold(builder, |builder, syscall| builder.syscall(syscall)); - let mut machine = AsmMachine::new(builder.build(), None); - let bytes = machine.load_program(&program, args).expect("load program"); - machine - .machine - .add_cycles(transferred_byte_cycles(bytes)) - .expect("load program cycles"); - machine.machine.set_running(true); - let h = GdbHandler::new(machine); - process_packets_from(stream.try_clone().unwrap(), stream, h); - } - } -} - -fn get_script_group<'a, DL: CellDataProvider + HeaderProvider>( - verifier: &'a TransactionScriptsVerifier<'a, DL>, - group_type: ScriptGroupType, - hash: &Byte32, -) -> Option<&'a ScriptGroup> { - for (t, h, g) in verifier.groups() { - if group_type == t && h == hash { - return Some(g); - } - } - None -} diff --git a/tests/omni_lock_rust/src/lib.rs b/tests/omni_lock_rust/src/lib.rs index 3e548dc..73abd67 100644 --- a/tests/omni_lock_rust/src/lib.rs +++ b/tests/omni_lock_rust/src/lib.rs @@ -1,3 +1,4 @@ -pub mod debug_utils; +pub mod blake2b; pub mod omni_lock; +pub mod schemas; pub mod xudt_rce_mol; diff --git a/tests/omni_lock_rust/src/omni_lock.rs b/tests/omni_lock_rust/src/omni_lock.rs index caadfe4..6a22911 100644 --- a/tests/omni_lock_rust/src/omni_lock.rs +++ b/tests/omni_lock_rust/src/omni_lock.rs @@ -36,9 +36,7 @@ impl ::core::fmt::Display for Auth { } impl ::core::default::Default for Auth { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + let v: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; Auth::new_unchecked(v.into()) } } @@ -436,8 +434,7 @@ impl molecule::prelude::Builder for AuthBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); Auth::new_unchecked(inner.into()) } } @@ -472,8 +469,8 @@ impl ::core::fmt::Display for Identity { impl ::core::default::Default for Identity { fn default() -> Self { let v: Vec = vec![ - 37, 0, 0, 0, 12, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 0, 0, 0, + 37, 0, 0, 0, 12, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, + 0, 0, ]; Identity::new_unchecked(v.into()) } @@ -538,9 +535,7 @@ impl molecule::prelude::Entity for Identity { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .identity(self.identity()) - .proofs(self.proofs()) + Self::new_builder().identity(self.identity()).proofs(self.proofs()) } } #[derive(Clone, Copy)] @@ -680,9 +675,7 @@ impl molecule::prelude::Builder for IdentityBuilder { type Entity = Identity; const NAME: &'static str = "IdentityBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.identity.as_slice().len() - + self.proofs.as_slice().len() + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.identity.as_slice().len() + self.proofs.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); @@ -701,8 +694,7 @@ impl molecule::prelude::Builder for IdentityBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); Identity::new_unchecked(inner.into()) } } @@ -851,21 +843,14 @@ impl molecule::prelude::Builder for IdentityOptBuilder { type Entity = IdentityOpt; const NAME: &'static str = "IdentityOptBuilder"; fn expected_length(&self) -> usize { - self.0 - .as_ref() - .map(|ref inner| inner.as_slice().len()) - .unwrap_or(0) + self.0.as_ref().map(|ref inner| inner.as_slice().len()).unwrap_or(0) } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - self.0 - .as_ref() - .map(|ref inner| writer.write_all(inner.as_slice())) - .unwrap_or(Ok(())) + self.0.as_ref().map(|ref inner| writer.write_all(inner.as_slice())).unwrap_or(Ok(())) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); IdentityOpt::new_unchecked(inner.into()) } } @@ -970,10 +955,7 @@ impl molecule::prelude::Entity for OmniLockWitnessLock { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .signature(self.signature()) - .omni_identity(self.omni_identity()) - .preimage(self.preimage()) + Self::new_builder().signature(self.signature()).omni_identity(self.omni_identity()).preimage(self.preimage()) } } #[derive(Clone, Copy)] @@ -1151,8 +1133,7 @@ impl molecule::prelude::Builder for OmniLockWitnessLockBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); OmniLockWitnessLock::new_unchecked(inner.into()) } } diff --git a/tests/omni_lock_rust/src/schemas/basic.rs b/tests/omni_lock_rust/src/schemas/basic.rs new file mode 100644 index 0000000..5e381ee --- /dev/null +++ b/tests/omni_lock_rust/src/schemas/basic.rs @@ -0,0 +1,5101 @@ +// Generated by Molecule 0.7.5 + +use super::blockchain::*; +use molecule::prelude::*; +#[derive(Clone)] +pub struct Hash(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Hash { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Hash { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Hash { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for Hash { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Hash::new_unchecked(v) + } +} +impl Hash { + const DEFAULT_VALUE: [u8; 32] = + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 32; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) + } + pub fn nth1(&self) -> Byte { + Byte::new_unchecked(self.0.slice(1..2)) + } + pub fn nth2(&self) -> Byte { + Byte::new_unchecked(self.0.slice(2..3)) + } + pub fn nth3(&self) -> Byte { + Byte::new_unchecked(self.0.slice(3..4)) + } + pub fn nth4(&self) -> Byte { + Byte::new_unchecked(self.0.slice(4..5)) + } + pub fn nth5(&self) -> Byte { + Byte::new_unchecked(self.0.slice(5..6)) + } + pub fn nth6(&self) -> Byte { + Byte::new_unchecked(self.0.slice(6..7)) + } + pub fn nth7(&self) -> Byte { + Byte::new_unchecked(self.0.slice(7..8)) + } + pub fn nth8(&self) -> Byte { + Byte::new_unchecked(self.0.slice(8..9)) + } + pub fn nth9(&self) -> Byte { + Byte::new_unchecked(self.0.slice(9..10)) + } + pub fn nth10(&self) -> Byte { + Byte::new_unchecked(self.0.slice(10..11)) + } + pub fn nth11(&self) -> Byte { + Byte::new_unchecked(self.0.slice(11..12)) + } + pub fn nth12(&self) -> Byte { + Byte::new_unchecked(self.0.slice(12..13)) + } + pub fn nth13(&self) -> Byte { + Byte::new_unchecked(self.0.slice(13..14)) + } + pub fn nth14(&self) -> Byte { + Byte::new_unchecked(self.0.slice(14..15)) + } + pub fn nth15(&self) -> Byte { + Byte::new_unchecked(self.0.slice(15..16)) + } + pub fn nth16(&self) -> Byte { + Byte::new_unchecked(self.0.slice(16..17)) + } + pub fn nth17(&self) -> Byte { + Byte::new_unchecked(self.0.slice(17..18)) + } + pub fn nth18(&self) -> Byte { + Byte::new_unchecked(self.0.slice(18..19)) + } + pub fn nth19(&self) -> Byte { + Byte::new_unchecked(self.0.slice(19..20)) + } + pub fn nth20(&self) -> Byte { + Byte::new_unchecked(self.0.slice(20..21)) + } + pub fn nth21(&self) -> Byte { + Byte::new_unchecked(self.0.slice(21..22)) + } + pub fn nth22(&self) -> Byte { + Byte::new_unchecked(self.0.slice(22..23)) + } + pub fn nth23(&self) -> Byte { + Byte::new_unchecked(self.0.slice(23..24)) + } + pub fn nth24(&self) -> Byte { + Byte::new_unchecked(self.0.slice(24..25)) + } + pub fn nth25(&self) -> Byte { + Byte::new_unchecked(self.0.slice(25..26)) + } + pub fn nth26(&self) -> Byte { + Byte::new_unchecked(self.0.slice(26..27)) + } + pub fn nth27(&self) -> Byte { + Byte::new_unchecked(self.0.slice(27..28)) + } + pub fn nth28(&self) -> Byte { + Byte::new_unchecked(self.0.slice(28..29)) + } + pub fn nth29(&self) -> Byte { + Byte::new_unchecked(self.0.slice(29..30)) + } + pub fn nth30(&self) -> Byte { + Byte::new_unchecked(self.0.slice(30..31)) + } + pub fn nth31(&self) -> Byte { + Byte::new_unchecked(self.0.slice(31..32)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> HashReader<'r> { + HashReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Hash { + type Builder = HashBuilder; + const NAME: &'static str = "Hash"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Hash(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + HashReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + HashReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set([ + self.nth0(), + self.nth1(), + self.nth2(), + self.nth3(), + self.nth4(), + self.nth5(), + self.nth6(), + self.nth7(), + self.nth8(), + self.nth9(), + self.nth10(), + self.nth11(), + self.nth12(), + self.nth13(), + self.nth14(), + self.nth15(), + self.nth16(), + self.nth17(), + self.nth18(), + self.nth19(), + self.nth20(), + self.nth21(), + self.nth22(), + self.nth23(), + self.nth24(), + self.nth25(), + self.nth26(), + self.nth27(), + self.nth28(), + self.nth29(), + self.nth30(), + self.nth31(), + ]) + } +} +#[derive(Clone, Copy)] +pub struct HashReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for HashReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for HashReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for HashReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> HashReader<'r> { + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 32; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) + } + pub fn nth1(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[1..2]) + } + pub fn nth2(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[2..3]) + } + pub fn nth3(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[3..4]) + } + pub fn nth4(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[4..5]) + } + pub fn nth5(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[5..6]) + } + pub fn nth6(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[6..7]) + } + pub fn nth7(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[7..8]) + } + pub fn nth8(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[8..9]) + } + pub fn nth9(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[9..10]) + } + pub fn nth10(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[10..11]) + } + pub fn nth11(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[11..12]) + } + pub fn nth12(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[12..13]) + } + pub fn nth13(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[13..14]) + } + pub fn nth14(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[14..15]) + } + pub fn nth15(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[15..16]) + } + pub fn nth16(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[16..17]) + } + pub fn nth17(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[17..18]) + } + pub fn nth18(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[18..19]) + } + pub fn nth19(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[19..20]) + } + pub fn nth20(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[20..21]) + } + pub fn nth21(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[21..22]) + } + pub fn nth22(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[22..23]) + } + pub fn nth23(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[23..24]) + } + pub fn nth24(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[24..25]) + } + pub fn nth25(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[25..26]) + } + pub fn nth26(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[26..27]) + } + pub fn nth27(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[27..28]) + } + pub fn nth28(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[28..29]) + } + pub fn nth29(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[29..30]) + } + pub fn nth30(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[30..31]) + } + pub fn nth31(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[31..32]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +impl<'r> molecule::prelude::Reader<'r> for HashReader<'r> { + type Entity = Hash; + const NAME: &'static str = "HashReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + HashReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +pub struct HashBuilder(pub(crate) [Byte; 32]); +impl ::core::fmt::Debug for HashBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for HashBuilder { + fn default() -> Self { + HashBuilder([ + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + Byte::default(), + ]) + } +} +impl HashBuilder { + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 32; + pub fn set(mut self, v: [Byte; 32]) -> Self { + self.0 = v; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } + pub fn nth1(mut self, v: Byte) -> Self { + self.0[1] = v; + self + } + pub fn nth2(mut self, v: Byte) -> Self { + self.0[2] = v; + self + } + pub fn nth3(mut self, v: Byte) -> Self { + self.0[3] = v; + self + } + pub fn nth4(mut self, v: Byte) -> Self { + self.0[4] = v; + self + } + pub fn nth5(mut self, v: Byte) -> Self { + self.0[5] = v; + self + } + pub fn nth6(mut self, v: Byte) -> Self { + self.0[6] = v; + self + } + pub fn nth7(mut self, v: Byte) -> Self { + self.0[7] = v; + self + } + pub fn nth8(mut self, v: Byte) -> Self { + self.0[8] = v; + self + } + pub fn nth9(mut self, v: Byte) -> Self { + self.0[9] = v; + self + } + pub fn nth10(mut self, v: Byte) -> Self { + self.0[10] = v; + self + } + pub fn nth11(mut self, v: Byte) -> Self { + self.0[11] = v; + self + } + pub fn nth12(mut self, v: Byte) -> Self { + self.0[12] = v; + self + } + pub fn nth13(mut self, v: Byte) -> Self { + self.0[13] = v; + self + } + pub fn nth14(mut self, v: Byte) -> Self { + self.0[14] = v; + self + } + pub fn nth15(mut self, v: Byte) -> Self { + self.0[15] = v; + self + } + pub fn nth16(mut self, v: Byte) -> Self { + self.0[16] = v; + self + } + pub fn nth17(mut self, v: Byte) -> Self { + self.0[17] = v; + self + } + pub fn nth18(mut self, v: Byte) -> Self { + self.0[18] = v; + self + } + pub fn nth19(mut self, v: Byte) -> Self { + self.0[19] = v; + self + } + pub fn nth20(mut self, v: Byte) -> Self { + self.0[20] = v; + self + } + pub fn nth21(mut self, v: Byte) -> Self { + self.0[21] = v; + self + } + pub fn nth22(mut self, v: Byte) -> Self { + self.0[22] = v; + self + } + pub fn nth23(mut self, v: Byte) -> Self { + self.0[23] = v; + self + } + pub fn nth24(mut self, v: Byte) -> Self { + self.0[24] = v; + self + } + pub fn nth25(mut self, v: Byte) -> Self { + self.0[25] = v; + self + } + pub fn nth26(mut self, v: Byte) -> Self { + self.0[26] = v; + self + } + pub fn nth27(mut self, v: Byte) -> Self { + self.0[27] = v; + self + } + pub fn nth28(mut self, v: Byte) -> Self { + self.0[28] = v; + self + } + pub fn nth29(mut self, v: Byte) -> Self { + self.0[29] = v; + self + } + pub fn nth30(mut self, v: Byte) -> Self { + self.0[30] = v; + self + } + pub fn nth31(mut self, v: Byte) -> Self { + self.0[31] = v; + self + } +} +impl molecule::prelude::Builder for HashBuilder { + type Entity = Hash; + const NAME: &'static str = "HashBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.0[0].as_slice())?; + writer.write_all(self.0[1].as_slice())?; + writer.write_all(self.0[2].as_slice())?; + writer.write_all(self.0[3].as_slice())?; + writer.write_all(self.0[4].as_slice())?; + writer.write_all(self.0[5].as_slice())?; + writer.write_all(self.0[6].as_slice())?; + writer.write_all(self.0[7].as_slice())?; + writer.write_all(self.0[8].as_slice())?; + writer.write_all(self.0[9].as_slice())?; + writer.write_all(self.0[10].as_slice())?; + writer.write_all(self.0[11].as_slice())?; + writer.write_all(self.0[12].as_slice())?; + writer.write_all(self.0[13].as_slice())?; + writer.write_all(self.0[14].as_slice())?; + writer.write_all(self.0[15].as_slice())?; + writer.write_all(self.0[16].as_slice())?; + writer.write_all(self.0[17].as_slice())?; + writer.write_all(self.0[18].as_slice())?; + writer.write_all(self.0[19].as_slice())?; + writer.write_all(self.0[20].as_slice())?; + writer.write_all(self.0[21].as_slice())?; + writer.write_all(self.0[22].as_slice())?; + writer.write_all(self.0[23].as_slice())?; + writer.write_all(self.0[24].as_slice())?; + writer.write_all(self.0[25].as_slice())?; + writer.write_all(self.0[26].as_slice())?; + writer.write_all(self.0[27].as_slice())?; + writer.write_all(self.0[28].as_slice())?; + writer.write_all(self.0[29].as_slice())?; + writer.write_all(self.0[30].as_slice())?; + writer.write_all(self.0[31].as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Hash::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct String(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for String { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for String { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for String { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for String { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + String::new_unchecked(v) + } +} +impl String { + const DEFAULT_VALUE: [u8; 4] = [0, 0, 0, 0]; + pub const ITEM_SIZE: usize = 1; + pub fn total_size(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.item_count() + } + pub fn item_count(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> Byte { + let start = molecule::NUMBER_SIZE + Self::ITEM_SIZE * idx; + let end = start + Self::ITEM_SIZE; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.0.slice(molecule::NUMBER_SIZE..) + } + pub fn as_reader<'r>(&'r self) -> StringReader<'r> { + StringReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for String { + type Builder = StringBuilder; + const NAME: &'static str = "String"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + String(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StringReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StringReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct StringReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for StringReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for StringReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for StringReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> StringReader<'r> { + pub const ITEM_SIZE: usize = 1; + pub fn total_size(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.item_count() + } + pub fn item_count(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ByteReader<'r> { + let start = molecule::NUMBER_SIZE + Self::ITEM_SIZE * idx; + let end = start + Self::ITEM_SIZE; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn raw_data(&self) -> &'r [u8] { + &self.as_slice()[molecule::NUMBER_SIZE..] + } +} +impl<'r> molecule::prelude::Reader<'r> for StringReader<'r> { + type Entity = String; + const NAME: &'static str = "StringReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + StringReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_count = molecule::unpack_number(slice) as usize; + if item_count == 0 { + if slice_len != molecule::NUMBER_SIZE { + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE, slice_len); + } + return Ok(()); + } + let total_size = molecule::NUMBER_SIZE + Self::ITEM_SIZE * item_count; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct StringBuilder(pub(crate) Vec); +impl StringBuilder { + pub const ITEM_SIZE: usize = 1; + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: Byte) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: Byte) -> Option { + self.0.get_mut(index).map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for StringBuilder { + type Entity = String; + const NAME: &'static str = "StringBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + Self::ITEM_SIZE * self.0.len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.len() as molecule::Number))?; + for inner in &self.0[..] { + writer.write_all(inner.as_slice())?; + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + String::new_unchecked(inner.into()) + } +} +pub struct StringIterator(String, usize, usize); +impl ::core::iter::Iterator for StringIterator { + type Item = Byte; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for StringIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for String { + type Item = Byte; + type IntoIter = StringIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + StringIterator(self, 0, len) + } +} +#[derive(Clone)] +pub struct Uint32Opt(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Uint32Opt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Uint32Opt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Uint32Opt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl ::core::default::Default for Uint32Opt { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Uint32Opt::new_unchecked(v) + } +} +impl Uint32Opt { + const DEFAULT_VALUE: [u8; 0] = []; + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option { + if self.is_none() { + None + } else { + Some(Uint32::new_unchecked(self.0.clone())) + } + } + pub fn as_reader<'r>(&'r self) -> Uint32OptReader<'r> { + Uint32OptReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Uint32Opt { + type Builder = Uint32OptBuilder; + const NAME: &'static str = "Uint32Opt"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Uint32Opt(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Uint32OptReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Uint32OptReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_opt()) + } +} +#[derive(Clone, Copy)] +pub struct Uint32OptReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for Uint32OptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for Uint32OptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for Uint32OptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl<'r> Uint32OptReader<'r> { + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option> { + if self.is_none() { + None + } else { + Some(Uint32Reader::new_unchecked(self.as_slice())) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for Uint32OptReader<'r> { + type Entity = Uint32Opt; + const NAME: &'static str = "Uint32OptReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + Uint32OptReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + if !slice.is_empty() { + Uint32Reader::verify(&slice[..], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct Uint32OptBuilder(pub(crate) Option); +impl Uint32OptBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self + } +} +impl molecule::prelude::Builder for Uint32OptBuilder { + type Entity = Uint32Opt; + const NAME: &'static str = "Uint32OptBuilder"; + fn expected_length(&self) -> usize { + self.0.as_ref().map(|ref inner| inner.as_slice().len()).unwrap_or(0) + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + self.0.as_ref().map(|ref inner| writer.write_all(inner.as_slice())).unwrap_or(Ok(())) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Uint32Opt::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct Action(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Action { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Action { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Action { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "script_info_hash", self.script_info_hash())?; + write!(f, ", {}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "data", self.data())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Action { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Action::new_unchecked(v) + } +} +impl Action { + const DEFAULT_VALUE: [u8; 84] = [ + 84, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn script_info_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn script_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn data(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ActionReader<'r> { + ActionReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Action { + type Builder = ActionBuilder; + const NAME: &'static str = "Action"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Action(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ActionReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ActionReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().script_info_hash(self.script_info_hash()).script_hash(self.script_hash()).data(self.data()) + } +} +#[derive(Clone, Copy)] +pub struct ActionReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ActionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ActionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ActionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "script_info_hash", self.script_info_hash())?; + write!(f, ", {}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "data", self.data())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> ActionReader<'r> { + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn script_info_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn script_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn data(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ActionReader<'r> { + type Entity = Action; + const NAME: &'static str = "ActionReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ActionReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BytesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ActionBuilder { + pub(crate) script_info_hash: Byte32, + pub(crate) script_hash: Byte32, + pub(crate) data: Bytes, +} +impl ActionBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn script_info_hash(mut self, v: Byte32) -> Self { + self.script_info_hash = v; + self + } + pub fn script_hash(mut self, v: Byte32) -> Self { + self.script_hash = v; + self + } + pub fn data(mut self, v: Bytes) -> Self { + self.data = v; + self + } +} +impl molecule::prelude::Builder for ActionBuilder { + type Entity = Action; + const NAME: &'static str = "ActionBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.script_info_hash.as_slice().len() + + self.script_hash.as_slice().len() + + self.data.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.script_info_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.script_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.data.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.script_info_hash.as_slice())?; + writer.write_all(self.script_hash.as_slice())?; + writer.write_all(self.data.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Action::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ActionVec(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ActionVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ActionVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ActionVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for ActionVec { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ActionVec::new_unchecked(v) + } +} +impl ActionVec { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> Action { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + Action::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + Action::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> ActionVecReader<'r> { + ActionVecReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ActionVec { + type Builder = ActionVecBuilder; + const NAME: &'static str = "ActionVec"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ActionVec(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ActionVecReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ActionVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct ActionVecReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ActionVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ActionVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ActionVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> ActionVecReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ActionReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + ActionReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + ActionReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ActionVecReader<'r> { + type Entity = ActionVec; + const NAME: &'static str = "ActionVecReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ActionVecReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + ActionReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ActionVecBuilder(pub(crate) Vec); +impl ActionVecBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: Action) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: Action) -> Option { + self.0.get_mut(index).map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for ActionVecBuilder { + type Entity = ActionVec; + const NAME: &'static str = "ActionVecBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + self.0.iter().map(|inner| inner.as_slice().len()).sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number(molecule::NUMBER_SIZE as molecule::Number))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + (molecule::NUMBER_SIZE * (item_count + 1), Vec::with_capacity(item_count)), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ActionVec::new_unchecked(inner.into()) + } +} +pub struct ActionVecIterator(ActionVec, usize, usize); +impl ::core::iter::Iterator for ActionVecIterator { + type Item = Action; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for ActionVecIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for ActionVec { + type Item = Action; + type IntoIter = ActionVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + ActionVecIterator(self, 0, len) + } +} +impl<'r> ActionVecReader<'r> { + pub fn iter<'t>(&'t self) -> ActionVecReaderIterator<'t, 'r> { + ActionVecReaderIterator(&self, 0, self.len()) + } +} +pub struct ActionVecReaderIterator<'t, 'r>(&'t ActionVecReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for ActionVecReaderIterator<'t, 'r> { + type Item = ActionReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for ActionVecReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] +pub struct Message(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "actions", self.actions())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Message { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Message::new_unchecked(v) + } +} +impl Message { + const DEFAULT_VALUE: [u8; 12] = [12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0]; + pub const FIELD_COUNT: usize = 1; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn actions(&self) -> ActionVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[8..]) as usize; + ActionVec::new_unchecked(self.0.slice(start..end)) + } else { + ActionVec::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> MessageReader<'r> { + MessageReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Message { + type Builder = MessageBuilder; + const NAME: &'static str = "Message"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Message(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + MessageReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + MessageReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().actions(self.actions()) + } +} +#[derive(Clone, Copy)] +pub struct MessageReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "actions", self.actions())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> MessageReader<'r> { + pub const FIELD_COUNT: usize = 1; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn actions(&self) -> ActionVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[8..]) as usize; + ActionVecReader::new_unchecked(&self.as_slice()[start..end]) + } else { + ActionVecReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for MessageReader<'r> { + type Entity = Message; + const NAME: &'static str = "MessageReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + MessageReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ActionVecReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct MessageBuilder { + pub(crate) actions: ActionVec, +} +impl MessageBuilder { + pub const FIELD_COUNT: usize = 1; + pub fn actions(mut self, v: ActionVec) -> Self { + self.actions = v; + self + } +} +impl molecule::prelude::Builder for MessageBuilder { + type Entity = Message; + const NAME: &'static str = "MessageBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.actions.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.actions.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.actions.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Message::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ScriptInfo(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ScriptInfo { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ScriptInfo { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ScriptInfo { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "name", self.name())?; + write!(f, ", {}: {}", "url", self.url())?; + write!(f, ", {}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "schema", self.schema())?; + write!(f, ", {}: {}", "message_type", self.message_type())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for ScriptInfo { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ScriptInfo::new_unchecked(v) + } +} +impl ScriptInfo { + const DEFAULT_VALUE: [u8; 72] = [ + 72, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn name(&self) -> String { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + String::new_unchecked(self.0.slice(start..end)) + } + pub fn url(&self) -> String { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + String::new_unchecked(self.0.slice(start..end)) + } + pub fn script_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn schema(&self) -> String { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + String::new_unchecked(self.0.slice(start..end)) + } + pub fn message_type(&self) -> String { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + String::new_unchecked(self.0.slice(start..end)) + } else { + String::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ScriptInfoReader<'r> { + ScriptInfoReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ScriptInfo { + type Builder = ScriptInfoBuilder; + const NAME: &'static str = "ScriptInfo"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ScriptInfo(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ScriptInfoReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ScriptInfoReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .name(self.name()) + .url(self.url()) + .script_hash(self.script_hash()) + .schema(self.schema()) + .message_type(self.message_type()) + } +} +#[derive(Clone, Copy)] +pub struct ScriptInfoReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ScriptInfoReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ScriptInfoReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ScriptInfoReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "name", self.name())?; + write!(f, ", {}: {}", "url", self.url())?; + write!(f, ", {}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "schema", self.schema())?; + write!(f, ", {}: {}", "message_type", self.message_type())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> ScriptInfoReader<'r> { + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn name(&self) -> StringReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + StringReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn url(&self) -> StringReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + StringReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn script_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn schema(&self) -> StringReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + StringReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn message_type(&self) -> StringReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + StringReader::new_unchecked(&self.as_slice()[start..end]) + } else { + StringReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ScriptInfoReader<'r> { + type Entity = ScriptInfo; + const NAME: &'static str = "ScriptInfoReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ScriptInfoReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + StringReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + StringReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + StringReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + StringReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ScriptInfoBuilder { + pub(crate) name: String, + pub(crate) url: String, + pub(crate) script_hash: Byte32, + pub(crate) schema: String, + pub(crate) message_type: String, +} +impl ScriptInfoBuilder { + pub const FIELD_COUNT: usize = 5; + pub fn name(mut self, v: String) -> Self { + self.name = v; + self + } + pub fn url(mut self, v: String) -> Self { + self.url = v; + self + } + pub fn script_hash(mut self, v: Byte32) -> Self { + self.script_hash = v; + self + } + pub fn schema(mut self, v: String) -> Self { + self.schema = v; + self + } + pub fn message_type(mut self, v: String) -> Self { + self.message_type = v; + self + } +} +impl molecule::prelude::Builder for ScriptInfoBuilder { + type Entity = ScriptInfo; + const NAME: &'static str = "ScriptInfoBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.name.as_slice().len() + + self.url.as_slice().len() + + self.script_hash.as_slice().len() + + self.schema.as_slice().len() + + self.message_type.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.name.as_slice().len(); + offsets.push(total_size); + total_size += self.url.as_slice().len(); + offsets.push(total_size); + total_size += self.script_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.schema.as_slice().len(); + offsets.push(total_size); + total_size += self.message_type.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.name.as_slice())?; + writer.write_all(self.url.as_slice())?; + writer.write_all(self.script_hash.as_slice())?; + writer.write_all(self.schema.as_slice())?; + writer.write_all(self.message_type.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ScriptInfo::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ScriptInfoVec(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ScriptInfoVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ScriptInfoVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ScriptInfoVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for ScriptInfoVec { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ScriptInfoVec::new_unchecked(v) + } +} +impl ScriptInfoVec { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ScriptInfo { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + ScriptInfo::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + ScriptInfo::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> ScriptInfoVecReader<'r> { + ScriptInfoVecReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ScriptInfoVec { + type Builder = ScriptInfoVecBuilder; + const NAME: &'static str = "ScriptInfoVec"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ScriptInfoVec(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ScriptInfoVecReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ScriptInfoVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct ScriptInfoVecReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ScriptInfoVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ScriptInfoVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ScriptInfoVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> ScriptInfoVecReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ScriptInfoReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + ScriptInfoReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + ScriptInfoReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ScriptInfoVecReader<'r> { + type Entity = ScriptInfoVec; + const NAME: &'static str = "ScriptInfoVecReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ScriptInfoVecReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + ScriptInfoReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ScriptInfoVecBuilder(pub(crate) Vec); +impl ScriptInfoVecBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: ScriptInfo) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: ScriptInfo) -> Option { + self.0.get_mut(index).map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for ScriptInfoVecBuilder { + type Entity = ScriptInfoVec; + const NAME: &'static str = "ScriptInfoVecBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + self.0.iter().map(|inner| inner.as_slice().len()).sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number(molecule::NUMBER_SIZE as molecule::Number))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + (molecule::NUMBER_SIZE * (item_count + 1), Vec::with_capacity(item_count)), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ScriptInfoVec::new_unchecked(inner.into()) + } +} +pub struct ScriptInfoVecIterator(ScriptInfoVec, usize, usize); +impl ::core::iter::Iterator for ScriptInfoVecIterator { + type Item = ScriptInfo; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for ScriptInfoVecIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for ScriptInfoVec { + type Item = ScriptInfo; + type IntoIter = ScriptInfoVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + ScriptInfoVecIterator(self, 0, len) + } +} +impl<'r> ScriptInfoVecReader<'r> { + pub fn iter<'t>(&'t self) -> ScriptInfoVecReaderIterator<'t, 'r> { + ScriptInfoVecReaderIterator(&self, 0, self.len()) + } +} +pub struct ScriptInfoVecReaderIterator<'t, 'r>(&'t ScriptInfoVecReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for ScriptInfoVecReaderIterator<'t, 'r> { + type Item = ScriptInfoReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for ScriptInfoVecReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] +pub struct ResolvedInputs(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ResolvedInputs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ResolvedInputs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ResolvedInputs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "outputs", self.outputs())?; + write!(f, ", {}: {}", "outputs_data", self.outputs_data())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for ResolvedInputs { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ResolvedInputs::new_unchecked(v) + } +} +impl ResolvedInputs { + const DEFAULT_VALUE: [u8; 20] = [20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn outputs(&self) -> CellOutputVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + CellOutputVec::new_unchecked(self.0.slice(start..end)) + } + pub fn outputs_data(&self) -> BytesVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesVec::new_unchecked(self.0.slice(start..end)) + } else { + BytesVec::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ResolvedInputsReader<'r> { + ResolvedInputsReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ResolvedInputs { + type Builder = ResolvedInputsBuilder; + const NAME: &'static str = "ResolvedInputs"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ResolvedInputs(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ResolvedInputsReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ResolvedInputsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().outputs(self.outputs()).outputs_data(self.outputs_data()) + } +} +#[derive(Clone, Copy)] +pub struct ResolvedInputsReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ResolvedInputsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ResolvedInputsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ResolvedInputsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "outputs", self.outputs())?; + write!(f, ", {}: {}", "outputs_data", self.outputs_data())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> ResolvedInputsReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn outputs(&self) -> CellOutputVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + CellOutputVecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn outputs_data(&self) -> BytesVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesVecReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesVecReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ResolvedInputsReader<'r> { + type Entity = ResolvedInputs; + const NAME: &'static str = "ResolvedInputsReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ResolvedInputsReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + CellOutputVecReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ResolvedInputsBuilder { + pub(crate) outputs: CellOutputVec, + pub(crate) outputs_data: BytesVec, +} +impl ResolvedInputsBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn outputs(mut self, v: CellOutputVec) -> Self { + self.outputs = v; + self + } + pub fn outputs_data(mut self, v: BytesVec) -> Self { + self.outputs_data = v; + self + } +} +impl molecule::prelude::Builder for ResolvedInputsBuilder { + type Entity = ResolvedInputs; + const NAME: &'static str = "ResolvedInputsBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.outputs.as_slice().len() + + self.outputs_data.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.outputs.as_slice().len(); + offsets.push(total_size); + total_size += self.outputs_data.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.outputs.as_slice())?; + writer.write_all(self.outputs_data.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ResolvedInputs::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct BuildingPacketV1(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for BuildingPacketV1 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for BuildingPacketV1 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for BuildingPacketV1 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "message", self.message())?; + write!(f, ", {}: {}", "payload", self.payload())?; + write!(f, ", {}: {}", "resolved_inputs", self.resolved_inputs())?; + write!(f, ", {}: {}", "change_output", self.change_output())?; + write!(f, ", {}: {}", "script_infos", self.script_infos())?; + write!(f, ", {}: {}", "lock_actions", self.lock_actions())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for BuildingPacketV1 { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + BuildingPacketV1::new_unchecked(v) + } +} +impl BuildingPacketV1 { + const DEFAULT_VALUE: [u8; 136] = [ + 136, 0, 0, 0, 28, 0, 0, 0, 40, 0, 0, 0, 108, 0, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 132, 0, 0, 0, 12, 0, 0, 0, 8, + 0, 0, 0, 4, 0, 0, 0, 68, 0, 0, 0, 12, 0, 0, 0, 64, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, + 40, 0, 0, 0, 44, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, + 4, 0, 0, 0, 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 6; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn message(&self) -> Message { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Message::new_unchecked(self.0.slice(start..end)) + } + pub fn payload(&self) -> Transaction { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Transaction::new_unchecked(self.0.slice(start..end)) + } + pub fn resolved_inputs(&self) -> ResolvedInputs { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + ResolvedInputs::new_unchecked(self.0.slice(start..end)) + } + pub fn change_output(&self) -> Uint32Opt { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32Opt::new_unchecked(self.0.slice(start..end)) + } + pub fn script_infos(&self) -> ScriptInfoVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + ScriptInfoVec::new_unchecked(self.0.slice(start..end)) + } + pub fn lock_actions(&self) -> ActionVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + ActionVec::new_unchecked(self.0.slice(start..end)) + } else { + ActionVec::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> BuildingPacketV1Reader<'r> { + BuildingPacketV1Reader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for BuildingPacketV1 { + type Builder = BuildingPacketV1Builder; + const NAME: &'static str = "BuildingPacketV1"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + BuildingPacketV1(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BuildingPacketV1Reader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BuildingPacketV1Reader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .message(self.message()) + .payload(self.payload()) + .resolved_inputs(self.resolved_inputs()) + .change_output(self.change_output()) + .script_infos(self.script_infos()) + .lock_actions(self.lock_actions()) + } +} +#[derive(Clone, Copy)] +pub struct BuildingPacketV1Reader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BuildingPacketV1Reader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for BuildingPacketV1Reader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for BuildingPacketV1Reader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "message", self.message())?; + write!(f, ", {}: {}", "payload", self.payload())?; + write!(f, ", {}: {}", "resolved_inputs", self.resolved_inputs())?; + write!(f, ", {}: {}", "change_output", self.change_output())?; + write!(f, ", {}: {}", "script_infos", self.script_infos())?; + write!(f, ", {}: {}", "lock_actions", self.lock_actions())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> BuildingPacketV1Reader<'r> { + pub const FIELD_COUNT: usize = 6; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn message(&self) -> MessageReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + MessageReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn payload(&self) -> TransactionReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + TransactionReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn resolved_inputs(&self) -> ResolvedInputsReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + ResolvedInputsReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn change_output(&self) -> Uint32OptReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32OptReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn script_infos(&self) -> ScriptInfoVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + ScriptInfoVecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn lock_actions(&self) -> ActionVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + ActionVecReader::new_unchecked(&self.as_slice()[start..end]) + } else { + ActionVecReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for BuildingPacketV1Reader<'r> { + type Entity = BuildingPacketV1; + const NAME: &'static str = "BuildingPacketV1Reader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + BuildingPacketV1Reader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + MessageReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + TransactionReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + ResolvedInputsReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Uint32OptReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + ScriptInfoVecReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + ActionVecReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct BuildingPacketV1Builder { + pub(crate) message: Message, + pub(crate) payload: Transaction, + pub(crate) resolved_inputs: ResolvedInputs, + pub(crate) change_output: Uint32Opt, + pub(crate) script_infos: ScriptInfoVec, + pub(crate) lock_actions: ActionVec, +} +impl BuildingPacketV1Builder { + pub const FIELD_COUNT: usize = 6; + pub fn message(mut self, v: Message) -> Self { + self.message = v; + self + } + pub fn payload(mut self, v: Transaction) -> Self { + self.payload = v; + self + } + pub fn resolved_inputs(mut self, v: ResolvedInputs) -> Self { + self.resolved_inputs = v; + self + } + pub fn change_output(mut self, v: Uint32Opt) -> Self { + self.change_output = v; + self + } + pub fn script_infos(mut self, v: ScriptInfoVec) -> Self { + self.script_infos = v; + self + } + pub fn lock_actions(mut self, v: ActionVec) -> Self { + self.lock_actions = v; + self + } +} +impl molecule::prelude::Builder for BuildingPacketV1Builder { + type Entity = BuildingPacketV1; + const NAME: &'static str = "BuildingPacketV1Builder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.message.as_slice().len() + + self.payload.as_slice().len() + + self.resolved_inputs.as_slice().len() + + self.change_output.as_slice().len() + + self.script_infos.as_slice().len() + + self.lock_actions.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.message.as_slice().len(); + offsets.push(total_size); + total_size += self.payload.as_slice().len(); + offsets.push(total_size); + total_size += self.resolved_inputs.as_slice().len(); + offsets.push(total_size); + total_size += self.change_output.as_slice().len(); + offsets.push(total_size); + total_size += self.script_infos.as_slice().len(); + offsets.push(total_size); + total_size += self.lock_actions.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.message.as_slice())?; + writer.write_all(self.payload.as_slice())?; + writer.write_all(self.resolved_inputs.as_slice())?; + writer.write_all(self.change_output.as_slice())?; + writer.write_all(self.script_infos.as_slice())?; + writer.write_all(self.lock_actions.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + BuildingPacketV1::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct BuildingPacket(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for BuildingPacket { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for BuildingPacket { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for BuildingPacket { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl ::core::default::Default for BuildingPacket { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + BuildingPacket::new_unchecked(v) + } +} +impl BuildingPacket { + const DEFAULT_VALUE: [u8; 140] = [ + 0, 0, 0, 0, 136, 0, 0, 0, 28, 0, 0, 0, 40, 0, 0, 0, 108, 0, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 132, 0, 0, 0, 12, + 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 68, 0, 0, 0, 12, 0, 0, 0, 64, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, + 36, 0, 0, 0, 40, 0, 0, 0, 44, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + 4, 0, 0, 0, 4, 0, 0, 0, 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, + ]; + pub const ITEMS_COUNT: usize = 1; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> BuildingPacketUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 0 => BuildingPacketV1::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } + pub fn as_reader<'r>(&'r self) -> BuildingPacketReader<'r> { + BuildingPacketReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for BuildingPacket { + type Builder = BuildingPacketBuilder; + const NAME: &'static str = "BuildingPacket"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + BuildingPacket(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BuildingPacketReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BuildingPacketReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_enum()) + } +} +#[derive(Clone, Copy)] +pub struct BuildingPacketReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BuildingPacketReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for BuildingPacketReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for BuildingPacketReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl<'r> BuildingPacketReader<'r> { + pub const ITEMS_COUNT: usize = 1; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> BuildingPacketUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 0 => BuildingPacketV1Reader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } +} +impl<'r> molecule::prelude::Reader<'r> for BuildingPacketReader<'r> { + type Entity = BuildingPacket; + const NAME: &'static str = "BuildingPacketReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + BuildingPacketReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 0 => BuildingPacketV1Reader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct BuildingPacketBuilder(pub(crate) BuildingPacketUnion); +impl BuildingPacketBuilder { + pub const ITEMS_COUNT: usize = 1; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); + self + } +} +impl molecule::prelude::Builder for BuildingPacketBuilder { + type Entity = BuildingPacket; + const NAME: &'static str = "BuildingPacketBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + self.0.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + BuildingPacket::new_unchecked(inner.into()) + } +} +#[derive(Debug, Clone)] +pub enum BuildingPacketUnion { + BuildingPacketV1(BuildingPacketV1), +} +#[derive(Debug, Clone, Copy)] +pub enum BuildingPacketUnionReader<'r> { + BuildingPacketV1(BuildingPacketV1Reader<'r>), +} +impl ::core::default::Default for BuildingPacketUnion { + fn default() -> Self { + BuildingPacketUnion::BuildingPacketV1(::core::default::Default::default()) + } +} +impl ::core::fmt::Display for BuildingPacketUnion { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BuildingPacketUnion::BuildingPacketV1(ref item) => { + write!(f, "{}::{}({})", Self::NAME, BuildingPacketV1::NAME, item) + } + } + } +} +impl<'r> ::core::fmt::Display for BuildingPacketUnionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BuildingPacketUnionReader::BuildingPacketV1(ref item) => { + write!(f, "{}::{}({})", Self::NAME, BuildingPacketV1::NAME, item) + } + } + } +} +impl BuildingPacketUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BuildingPacketUnion::BuildingPacketV1(ref item) => write!(f, "{}", item), + } + } +} +impl<'r> BuildingPacketUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BuildingPacketUnionReader::BuildingPacketV1(ref item) => write!(f, "{}", item), + } + } +} +impl ::core::convert::From for BuildingPacketUnion { + fn from(item: BuildingPacketV1) -> Self { + BuildingPacketUnion::BuildingPacketV1(item) + } +} +impl<'r> ::core::convert::From> for BuildingPacketUnionReader<'r> { + fn from(item: BuildingPacketV1Reader<'r>) -> Self { + BuildingPacketUnionReader::BuildingPacketV1(item) + } +} +impl BuildingPacketUnion { + pub const NAME: &'static str = "BuildingPacketUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + BuildingPacketUnion::BuildingPacketV1(item) => item.as_bytes(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + BuildingPacketUnion::BuildingPacketV1(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + BuildingPacketUnion::BuildingPacketV1(_) => 0, + } + } + pub fn item_name(&self) -> &str { + match self { + BuildingPacketUnion::BuildingPacketV1(_) => "BuildingPacketV1", + } + } + pub fn as_reader<'r>(&'r self) -> BuildingPacketUnionReader<'r> { + match self { + BuildingPacketUnion::BuildingPacketV1(item) => item.as_reader().into(), + } + } +} +impl<'r> BuildingPacketUnionReader<'r> { + pub const NAME: &'r str = "BuildingPacketUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + BuildingPacketUnionReader::BuildingPacketV1(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + BuildingPacketUnionReader::BuildingPacketV1(_) => 0, + } + } + pub fn item_name(&self) -> &str { + match self { + BuildingPacketUnionReader::BuildingPacketV1(_) => "BuildingPacketV1", + } + } +} +#[derive(Clone)] +pub struct SighashAll(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SighashAll { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for SighashAll { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SighashAll { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "message", self.message())?; + write!(f, ", {}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for SighashAll { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SighashAll::new_unchecked(v) + } +} +impl SighashAll { + const DEFAULT_VALUE: [u8; 28] = + [28, 0, 0, 0, 12, 0, 0, 0, 24, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn message(&self) -> Message { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Message::new_unchecked(self.0.slice(start..end)) + } + pub fn seal(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> SighashAllReader<'r> { + SighashAllReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SighashAll { + type Builder = SighashAllBuilder; + const NAME: &'static str = "SighashAll"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SighashAll(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SighashAllReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SighashAllReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().message(self.message()).seal(self.seal()) + } +} +#[derive(Clone, Copy)] +pub struct SighashAllReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SighashAllReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for SighashAllReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SighashAllReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "message", self.message())?; + write!(f, ", {}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> SighashAllReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn message(&self) -> MessageReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + MessageReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn seal(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SighashAllReader<'r> { + type Entity = SighashAll; + const NAME: &'static str = "SighashAllReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SighashAllReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + MessageReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct SighashAllBuilder { + pub(crate) message: Message, + pub(crate) seal: Bytes, +} +impl SighashAllBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn message(mut self, v: Message) -> Self { + self.message = v; + self + } + pub fn seal(mut self, v: Bytes) -> Self { + self.seal = v; + self + } +} +impl molecule::prelude::Builder for SighashAllBuilder { + type Entity = SighashAll; + const NAME: &'static str = "SighashAllBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.message.as_slice().len() + self.seal.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.message.as_slice().len(); + offsets.push(total_size); + total_size += self.seal.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.message.as_slice())?; + writer.write_all(self.seal.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + SighashAll::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct SighashAllOnly(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SighashAllOnly { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for SighashAllOnly { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SighashAllOnly { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for SighashAllOnly { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SighashAllOnly::new_unchecked(v) + } +} +impl SighashAllOnly { + const DEFAULT_VALUE: [u8; 12] = [12, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0]; + pub const FIELD_COUNT: usize = 1; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn seal(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[8..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> SighashAllOnlyReader<'r> { + SighashAllOnlyReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SighashAllOnly { + type Builder = SighashAllOnlyBuilder; + const NAME: &'static str = "SighashAllOnly"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SighashAllOnly(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SighashAllOnlyReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SighashAllOnlyReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().seal(self.seal()) + } +} +#[derive(Clone, Copy)] +pub struct SighashAllOnlyReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SighashAllOnlyReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for SighashAllOnlyReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SighashAllOnlyReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> SighashAllOnlyReader<'r> { + pub const FIELD_COUNT: usize = 1; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn seal(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[8..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SighashAllOnlyReader<'r> { + type Entity = SighashAllOnly; + const NAME: &'static str = "SighashAllOnlyReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SighashAllOnlyReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct SighashAllOnlyBuilder { + pub(crate) seal: Bytes, +} +impl SighashAllOnlyBuilder { + pub const FIELD_COUNT: usize = 1; + pub fn seal(mut self, v: Bytes) -> Self { + self.seal = v; + self + } +} +impl molecule::prelude::Builder for SighashAllOnlyBuilder { + type Entity = SighashAllOnly; + const NAME: &'static str = "SighashAllOnlyBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.seal.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.seal.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.seal.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + SighashAllOnly::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct SealPair(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SealPair { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for SealPair { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SealPair { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for SealPair { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SealPair::new_unchecked(v) + } +} +impl SealPair { + const DEFAULT_VALUE: [u8; 48] = [ + 48, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn script_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn seal(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> SealPairReader<'r> { + SealPairReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SealPair { + type Builder = SealPairBuilder; + const NAME: &'static str = "SealPair"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SealPair(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SealPairReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SealPairReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().script_hash(self.script_hash()).seal(self.seal()) + } +} +#[derive(Clone, Copy)] +pub struct SealPairReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SealPairReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for SealPairReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SealPairReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "script_hash", self.script_hash())?; + write!(f, ", {}: {}", "seal", self.seal())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> SealPairReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn script_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn seal(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SealPairReader<'r> { + type Entity = SealPair; + const NAME: &'static str = "SealPairReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SealPairReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct SealPairBuilder { + pub(crate) script_hash: Byte32, + pub(crate) seal: Bytes, +} +impl SealPairBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn script_hash(mut self, v: Byte32) -> Self { + self.script_hash = v; + self + } + pub fn seal(mut self, v: Bytes) -> Self { + self.seal = v; + self + } +} +impl molecule::prelude::Builder for SealPairBuilder { + type Entity = SealPair; + const NAME: &'static str = "SealPairBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.script_hash.as_slice().len() + self.seal.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.script_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.seal.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.script_hash.as_slice())?; + writer.write_all(self.seal.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + SealPair::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct SealPairVec(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SealPairVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for SealPairVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SealPairVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for SealPairVec { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SealPairVec::new_unchecked(v) + } +} +impl SealPairVec { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> SealPair { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + SealPair::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + SealPair::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> SealPairVecReader<'r> { + SealPairVecReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SealPairVec { + type Builder = SealPairVecBuilder; + const NAME: &'static str = "SealPairVec"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SealPairVec(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SealPairVecReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SealPairVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct SealPairVecReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SealPairVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for SealPairVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SealPairVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> SealPairVecReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> SealPairReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + SealPairReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + SealPairReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SealPairVecReader<'r> { + type Entity = SealPairVec; + const NAME: &'static str = "SealPairVecReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SealPairVecReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + SealPairReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct SealPairVecBuilder(pub(crate) Vec); +impl SealPairVecBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: SealPair) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: SealPair) -> Option { + self.0.get_mut(index).map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for SealPairVecBuilder { + type Entity = SealPairVec; + const NAME: &'static str = "SealPairVecBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + self.0.iter().map(|inner| inner.as_slice().len()).sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number(molecule::NUMBER_SIZE as molecule::Number))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + (molecule::NUMBER_SIZE * (item_count + 1), Vec::with_capacity(item_count)), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + SealPairVec::new_unchecked(inner.into()) + } +} +pub struct SealPairVecIterator(SealPairVec, usize, usize); +impl ::core::iter::Iterator for SealPairVecIterator { + type Item = SealPair; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for SealPairVecIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for SealPairVec { + type Item = SealPair; + type IntoIter = SealPairVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + SealPairVecIterator(self, 0, len) + } +} +impl<'r> SealPairVecReader<'r> { + pub fn iter<'t>(&'t self) -> SealPairVecReaderIterator<'t, 'r> { + SealPairVecReaderIterator(&self, 0, self.len()) + } +} +pub struct SealPairVecReaderIterator<'t, 'r>(&'t SealPairVecReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for SealPairVecReaderIterator<'t, 'r> { + type Item = SealPairReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for SealPairVecReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] +pub struct OtxStart(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for OtxStart { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for OtxStart { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for OtxStart { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "start_input_cell", self.start_input_cell())?; + write!(f, ", {}: {}", "start_output_cell", self.start_output_cell())?; + write!(f, ", {}: {}", "start_cell_deps", self.start_cell_deps())?; + write!(f, ", {}: {}", "start_header_deps", self.start_header_deps())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for OtxStart { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + OtxStart::new_unchecked(v) + } +} +impl OtxStart { + const DEFAULT_VALUE: [u8; 36] = [ + 36, 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn start_input_cell(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn start_output_cell(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn start_cell_deps(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn start_header_deps(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } else { + Uint32::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> OtxStartReader<'r> { + OtxStartReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for OtxStart { + type Builder = OtxStartBuilder; + const NAME: &'static str = "OtxStart"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + OtxStart(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OtxStartReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OtxStartReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .start_input_cell(self.start_input_cell()) + .start_output_cell(self.start_output_cell()) + .start_cell_deps(self.start_cell_deps()) + .start_header_deps(self.start_header_deps()) + } +} +#[derive(Clone, Copy)] +pub struct OtxStartReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for OtxStartReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for OtxStartReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for OtxStartReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "start_input_cell", self.start_input_cell())?; + write!(f, ", {}: {}", "start_output_cell", self.start_output_cell())?; + write!(f, ", {}: {}", "start_cell_deps", self.start_cell_deps())?; + write!(f, ", {}: {}", "start_header_deps", self.start_header_deps())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> OtxStartReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn start_input_cell(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn start_output_cell(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn start_cell_deps(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn start_header_deps(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } else { + Uint32Reader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for OtxStartReader<'r> { + type Entity = OtxStart; + const NAME: &'static str = "OtxStartReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + OtxStartReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Uint32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Uint32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Uint32Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct OtxStartBuilder { + pub(crate) start_input_cell: Uint32, + pub(crate) start_output_cell: Uint32, + pub(crate) start_cell_deps: Uint32, + pub(crate) start_header_deps: Uint32, +} +impl OtxStartBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn start_input_cell(mut self, v: Uint32) -> Self { + self.start_input_cell = v; + self + } + pub fn start_output_cell(mut self, v: Uint32) -> Self { + self.start_output_cell = v; + self + } + pub fn start_cell_deps(mut self, v: Uint32) -> Self { + self.start_cell_deps = v; + self + } + pub fn start_header_deps(mut self, v: Uint32) -> Self { + self.start_header_deps = v; + self + } +} +impl molecule::prelude::Builder for OtxStartBuilder { + type Entity = OtxStart; + const NAME: &'static str = "OtxStartBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.start_input_cell.as_slice().len() + + self.start_output_cell.as_slice().len() + + self.start_cell_deps.as_slice().len() + + self.start_header_deps.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.start_input_cell.as_slice().len(); + offsets.push(total_size); + total_size += self.start_output_cell.as_slice().len(); + offsets.push(total_size); + total_size += self.start_cell_deps.as_slice().len(); + offsets.push(total_size); + total_size += self.start_header_deps.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.start_input_cell.as_slice())?; + writer.write_all(self.start_output_cell.as_slice())?; + writer.write_all(self.start_cell_deps.as_slice())?; + writer.write_all(self.start_header_deps.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + OtxStart::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct Otx(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Otx { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Otx { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Otx { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "input_cells", self.input_cells())?; + write!(f, ", {}: {}", "output_cells", self.output_cells())?; + write!(f, ", {}: {}", "cell_deps", self.cell_deps())?; + write!(f, ", {}: {}", "header_deps", self.header_deps())?; + write!(f, ", {}: {}", "message", self.message())?; + write!(f, ", {}: {}", "seals", self.seals())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Otx { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Otx::new_unchecked(v) + } +} +impl Otx { + const DEFAULT_VALUE: [u8; 60] = [ + 60, 0, 0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, 40, 0, 0, 0, 44, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 6; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn input_cells(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn output_cells(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn cell_deps(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn header_deps(&self) -> Uint32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32::new_unchecked(self.0.slice(start..end)) + } + pub fn message(&self) -> Message { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Message::new_unchecked(self.0.slice(start..end)) + } + pub fn seals(&self) -> SealPairVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + SealPairVec::new_unchecked(self.0.slice(start..end)) + } else { + SealPairVec::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> OtxReader<'r> { + OtxReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Otx { + type Builder = OtxBuilder; + const NAME: &'static str = "Otx"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Otx(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OtxReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + OtxReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .input_cells(self.input_cells()) + .output_cells(self.output_cells()) + .cell_deps(self.cell_deps()) + .header_deps(self.header_deps()) + .message(self.message()) + .seals(self.seals()) + } +} +#[derive(Clone, Copy)] +pub struct OtxReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for OtxReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for OtxReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for OtxReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "input_cells", self.input_cells())?; + write!(f, ", {}: {}", "output_cells", self.output_cells())?; + write!(f, ", {}: {}", "cell_deps", self.cell_deps())?; + write!(f, ", {}: {}", "header_deps", self.header_deps())?; + write!(f, ", {}: {}", "message", self.message())?; + write!(f, ", {}: {}", "seals", self.seals())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> OtxReader<'r> { + pub const FIELD_COUNT: usize = 6; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn input_cells(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn output_cells(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn cell_deps(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn header_deps(&self) -> Uint32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn message(&self) -> MessageReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + MessageReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn seals(&self) -> SealPairVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + SealPairVecReader::new_unchecked(&self.as_slice()[start..end]) + } else { + SealPairVecReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for OtxReader<'r> { + type Entity = Otx; + const NAME: &'static str = "OtxReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + OtxReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Uint32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Uint32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Uint32Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + MessageReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + SealPairVecReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct OtxBuilder { + pub(crate) input_cells: Uint32, + pub(crate) output_cells: Uint32, + pub(crate) cell_deps: Uint32, + pub(crate) header_deps: Uint32, + pub(crate) message: Message, + pub(crate) seals: SealPairVec, +} +impl OtxBuilder { + pub const FIELD_COUNT: usize = 6; + pub fn input_cells(mut self, v: Uint32) -> Self { + self.input_cells = v; + self + } + pub fn output_cells(mut self, v: Uint32) -> Self { + self.output_cells = v; + self + } + pub fn cell_deps(mut self, v: Uint32) -> Self { + self.cell_deps = v; + self + } + pub fn header_deps(mut self, v: Uint32) -> Self { + self.header_deps = v; + self + } + pub fn message(mut self, v: Message) -> Self { + self.message = v; + self + } + pub fn seals(mut self, v: SealPairVec) -> Self { + self.seals = v; + self + } +} +impl molecule::prelude::Builder for OtxBuilder { + type Entity = Otx; + const NAME: &'static str = "OtxBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.input_cells.as_slice().len() + + self.output_cells.as_slice().len() + + self.cell_deps.as_slice().len() + + self.header_deps.as_slice().len() + + self.message.as_slice().len() + + self.seals.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.input_cells.as_slice().len(); + offsets.push(total_size); + total_size += self.output_cells.as_slice().len(); + offsets.push(total_size); + total_size += self.cell_deps.as_slice().len(); + offsets.push(total_size); + total_size += self.header_deps.as_slice().len(); + offsets.push(total_size); + total_size += self.message.as_slice().len(); + offsets.push(total_size); + total_size += self.seals.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.input_cells.as_slice())?; + writer.write_all(self.output_cells.as_slice())?; + writer.write_all(self.cell_deps.as_slice())?; + writer.write_all(self.header_deps.as_slice())?; + writer.write_all(self.message.as_slice())?; + writer.write_all(self.seals.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Otx::new_unchecked(inner.into()) + } +} diff --git a/tests/omni_lock_rust/src/schemas/mod.rs b/tests/omni_lock_rust/src/schemas/mod.rs new file mode 100644 index 0000000..4fc5711 --- /dev/null +++ b/tests/omni_lock_rust/src/schemas/mod.rs @@ -0,0 +1,3 @@ +pub use ckb_types::packed as blockchain; +pub mod basic; +pub mod top_level; diff --git a/tests/omni_lock_rust/src/schemas/top_level.rs b/tests/omni_lock_rust/src/schemas/top_level.rs new file mode 100644 index 0000000..545b60f --- /dev/null +++ b/tests/omni_lock_rust/src/schemas/top_level.rs @@ -0,0 +1,361 @@ +// Generated by Molecule 0.7.5 + +use super::basic::*; +use molecule::prelude::*; +#[derive(Clone)] +pub struct WitnessLayout(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for WitnessLayout { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for WitnessLayout { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for WitnessLayout { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl ::core::default::Default for WitnessLayout { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + WitnessLayout::new_unchecked(v) + } +} +impl WitnessLayout { + const DEFAULT_VALUE: [u8; 32] = + [1, 0, 0, 255, 28, 0, 0, 0, 12, 0, 0, 0, 24, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]; + pub const ITEMS_COUNT: usize = 4; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> WitnessLayoutUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 4278190081 => SighashAll::new_unchecked(inner).into(), + 4278190082 => SighashAllOnly::new_unchecked(inner).into(), + 4278190083 => Otx::new_unchecked(inner).into(), + 4278190084 => OtxStart::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } + pub fn as_reader<'r>(&'r self) -> WitnessLayoutReader<'r> { + WitnessLayoutReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for WitnessLayout { + type Builder = WitnessLayoutBuilder; + const NAME: &'static str = "WitnessLayout"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + WitnessLayout(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + WitnessLayoutReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + WitnessLayoutReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_enum()) + } +} +#[derive(Clone, Copy)] +pub struct WitnessLayoutReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for WitnessLayoutReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for WitnessLayoutReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for WitnessLayoutReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl<'r> WitnessLayoutReader<'r> { + pub const ITEMS_COUNT: usize = 4; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> WitnessLayoutUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 4278190081 => SighashAllReader::new_unchecked(inner).into(), + 4278190082 => SighashAllOnlyReader::new_unchecked(inner).into(), + 4278190083 => OtxReader::new_unchecked(inner).into(), + 4278190084 => OtxStartReader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } +} +impl<'r> molecule::prelude::Reader<'r> for WitnessLayoutReader<'r> { + type Entity = WitnessLayout; + const NAME: &'static str = "WitnessLayoutReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + WitnessLayoutReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 4278190081 => SighashAllReader::verify(inner_slice, compatible), + 4278190082 => SighashAllOnlyReader::verify(inner_slice, compatible), + 4278190083 => OtxReader::verify(inner_slice, compatible), + 4278190084 => OtxStartReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct WitnessLayoutBuilder(pub(crate) WitnessLayoutUnion); +impl WitnessLayoutBuilder { + pub const ITEMS_COUNT: usize = 4; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); + self + } +} +impl molecule::prelude::Builder for WitnessLayoutBuilder { + type Entity = WitnessLayout; + const NAME: &'static str = "WitnessLayoutBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + self.0.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + WitnessLayout::new_unchecked(inner.into()) + } +} +#[derive(Debug, Clone)] +pub enum WitnessLayoutUnion { + SighashAll(SighashAll), + SighashAllOnly(SighashAllOnly), + Otx(Otx), + OtxStart(OtxStart), +} +#[derive(Debug, Clone, Copy)] +pub enum WitnessLayoutUnionReader<'r> { + SighashAll(SighashAllReader<'r>), + SighashAllOnly(SighashAllOnlyReader<'r>), + Otx(OtxReader<'r>), + OtxStart(OtxStartReader<'r>), +} +impl ::core::default::Default for WitnessLayoutUnion { + fn default() -> Self { + WitnessLayoutUnion::SighashAll(::core::default::Default::default()) + } +} +impl ::core::fmt::Display for WitnessLayoutUnion { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + WitnessLayoutUnion::SighashAll(ref item) => { + write!(f, "{}::{}({})", Self::NAME, SighashAll::NAME, item) + } + WitnessLayoutUnion::SighashAllOnly(ref item) => { + write!(f, "{}::{}({})", Self::NAME, SighashAllOnly::NAME, item) + } + WitnessLayoutUnion::Otx(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Otx::NAME, item) + } + WitnessLayoutUnion::OtxStart(ref item) => { + write!(f, "{}::{}({})", Self::NAME, OtxStart::NAME, item) + } + } + } +} +impl<'r> ::core::fmt::Display for WitnessLayoutUnionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + WitnessLayoutUnionReader::SighashAll(ref item) => { + write!(f, "{}::{}({})", Self::NAME, SighashAll::NAME, item) + } + WitnessLayoutUnionReader::SighashAllOnly(ref item) => { + write!(f, "{}::{}({})", Self::NAME, SighashAllOnly::NAME, item) + } + WitnessLayoutUnionReader::Otx(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Otx::NAME, item) + } + WitnessLayoutUnionReader::OtxStart(ref item) => { + write!(f, "{}::{}({})", Self::NAME, OtxStart::NAME, item) + } + } + } +} +impl WitnessLayoutUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + WitnessLayoutUnion::SighashAll(ref item) => write!(f, "{}", item), + WitnessLayoutUnion::SighashAllOnly(ref item) => write!(f, "{}", item), + WitnessLayoutUnion::Otx(ref item) => write!(f, "{}", item), + WitnessLayoutUnion::OtxStart(ref item) => write!(f, "{}", item), + } + } +} +impl<'r> WitnessLayoutUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + WitnessLayoutUnionReader::SighashAll(ref item) => write!(f, "{}", item), + WitnessLayoutUnionReader::SighashAllOnly(ref item) => write!(f, "{}", item), + WitnessLayoutUnionReader::Otx(ref item) => write!(f, "{}", item), + WitnessLayoutUnionReader::OtxStart(ref item) => write!(f, "{}", item), + } + } +} +impl ::core::convert::From for WitnessLayoutUnion { + fn from(item: SighashAll) -> Self { + WitnessLayoutUnion::SighashAll(item) + } +} +impl ::core::convert::From for WitnessLayoutUnion { + fn from(item: SighashAllOnly) -> Self { + WitnessLayoutUnion::SighashAllOnly(item) + } +} +impl ::core::convert::From for WitnessLayoutUnion { + fn from(item: Otx) -> Self { + WitnessLayoutUnion::Otx(item) + } +} +impl ::core::convert::From for WitnessLayoutUnion { + fn from(item: OtxStart) -> Self { + WitnessLayoutUnion::OtxStart(item) + } +} +impl<'r> ::core::convert::From> for WitnessLayoutUnionReader<'r> { + fn from(item: SighashAllReader<'r>) -> Self { + WitnessLayoutUnionReader::SighashAll(item) + } +} +impl<'r> ::core::convert::From> for WitnessLayoutUnionReader<'r> { + fn from(item: SighashAllOnlyReader<'r>) -> Self { + WitnessLayoutUnionReader::SighashAllOnly(item) + } +} +impl<'r> ::core::convert::From> for WitnessLayoutUnionReader<'r> { + fn from(item: OtxReader<'r>) -> Self { + WitnessLayoutUnionReader::Otx(item) + } +} +impl<'r> ::core::convert::From> for WitnessLayoutUnionReader<'r> { + fn from(item: OtxStartReader<'r>) -> Self { + WitnessLayoutUnionReader::OtxStart(item) + } +} +impl WitnessLayoutUnion { + pub const NAME: &'static str = "WitnessLayoutUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + WitnessLayoutUnion::SighashAll(item) => item.as_bytes(), + WitnessLayoutUnion::SighashAllOnly(item) => item.as_bytes(), + WitnessLayoutUnion::Otx(item) => item.as_bytes(), + WitnessLayoutUnion::OtxStart(item) => item.as_bytes(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + WitnessLayoutUnion::SighashAll(item) => item.as_slice(), + WitnessLayoutUnion::SighashAllOnly(item) => item.as_slice(), + WitnessLayoutUnion::Otx(item) => item.as_slice(), + WitnessLayoutUnion::OtxStart(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + WitnessLayoutUnion::SighashAll(_) => 4278190081, + WitnessLayoutUnion::SighashAllOnly(_) => 4278190082, + WitnessLayoutUnion::Otx(_) => 4278190083, + WitnessLayoutUnion::OtxStart(_) => 4278190084, + } + } + pub fn item_name(&self) -> &str { + match self { + WitnessLayoutUnion::SighashAll(_) => "SighashAll", + WitnessLayoutUnion::SighashAllOnly(_) => "SighashAllOnly", + WitnessLayoutUnion::Otx(_) => "Otx", + WitnessLayoutUnion::OtxStart(_) => "OtxStart", + } + } + pub fn as_reader<'r>(&'r self) -> WitnessLayoutUnionReader<'r> { + match self { + WitnessLayoutUnion::SighashAll(item) => item.as_reader().into(), + WitnessLayoutUnion::SighashAllOnly(item) => item.as_reader().into(), + WitnessLayoutUnion::Otx(item) => item.as_reader().into(), + WitnessLayoutUnion::OtxStart(item) => item.as_reader().into(), + } + } +} +impl<'r> WitnessLayoutUnionReader<'r> { + pub const NAME: &'r str = "WitnessLayoutUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + WitnessLayoutUnionReader::SighashAll(item) => item.as_slice(), + WitnessLayoutUnionReader::SighashAllOnly(item) => item.as_slice(), + WitnessLayoutUnionReader::Otx(item) => item.as_slice(), + WitnessLayoutUnionReader::OtxStart(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + WitnessLayoutUnionReader::SighashAll(_) => 4278190081, + WitnessLayoutUnionReader::SighashAllOnly(_) => 4278190082, + WitnessLayoutUnionReader::Otx(_) => 4278190083, + WitnessLayoutUnionReader::OtxStart(_) => 4278190084, + } + } + pub fn item_name(&self) -> &str { + match self { + WitnessLayoutUnionReader::SighashAll(_) => "SighashAll", + WitnessLayoutUnionReader::SighashAllOnly(_) => "SighashAllOnly", + WitnessLayoutUnionReader::Otx(_) => "Otx", + WitnessLayoutUnionReader::OtxStart(_) => "OtxStart", + } + } +} diff --git a/tests/omni_lock_rust/src/xudt_rce_mol.rs b/tests/omni_lock_rust/src/xudt_rce_mol.rs index 7417bd8..ee038a2 100644 --- a/tests/omni_lock_rust/src/xudt_rce_mol.rs +++ b/tests/omni_lock_rust/src/xudt_rce_mol.rs @@ -200,12 +200,7 @@ impl<'r> molecule::prelude::Reader<'r> for ScriptVecReader<'r> { return Ok(()); } if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!( - Self, - TotalSizeNotMatch, - molecule::NUMBER_SIZE * 2, - slice_len - ); + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE * 2, slice_len); } let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { @@ -252,25 +247,15 @@ impl molecule::prelude::Builder for ScriptVecBuilder { type Entity = ScriptVec; const NAME: &'static str = "ScriptVecBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (self.0.len() + 1) - + self - .0 - .iter() - .map(|inner| inner.as_slice().len()) - .sum::() + molecule::NUMBER_SIZE * (self.0.len() + 1) + self.0.iter().map(|inner| inner.as_slice().len()).sum::() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let item_count = self.0.len(); if item_count == 0 { - writer.write_all(&molecule::pack_number( - molecule::NUMBER_SIZE as molecule::Number, - ))?; + writer.write_all(&molecule::pack_number(molecule::NUMBER_SIZE as molecule::Number))?; } else { let (total_size, offsets) = self.0.iter().fold( - ( - molecule::NUMBER_SIZE * (item_count + 1), - Vec::with_capacity(item_count), - ), + (molecule::NUMBER_SIZE * (item_count + 1), Vec::with_capacity(item_count)), |(start, mut offsets), inner| { offsets.push(start); (start + inner.as_slice().len(), offsets) @@ -288,8 +273,7 @@ impl molecule::prelude::Builder for ScriptVecBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); ScriptVec::new_unchecked(inner.into()) } } @@ -487,21 +471,14 @@ impl molecule::prelude::Builder for ScriptVecOptBuilder { type Entity = ScriptVecOpt; const NAME: &'static str = "ScriptVecOptBuilder"; fn expected_length(&self) -> usize { - self.0 - .as_ref() - .map(|ref inner| inner.as_slice().len()) - .unwrap_or(0) + self.0.as_ref().map(|ref inner| inner.as_slice().len()).unwrap_or(0) } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - self.0 - .as_ref() - .map(|ref inner| writer.write_all(inner.as_slice())) - .unwrap_or(Ok(())) + self.0.as_ref().map(|ref inner| writer.write_all(inner.as_slice())).unwrap_or(Ok(())) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); ScriptVecOpt::new_unchecked(inner.into()) } } @@ -599,9 +576,7 @@ impl molecule::prelude::Entity for XudtWitnessInput { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .raw_extension_data(self.raw_extension_data()) - .extension_data(self.extension_data()) + Self::new_builder().raw_extension_data(self.raw_extension_data()).extension_data(self.extension_data()) } } #[derive(Clone, Copy)] @@ -762,8 +737,7 @@ impl molecule::prelude::Builder for XudtWitnessInputBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); XudtWitnessInput::new_unchecked(inner.into()) } } @@ -793,10 +767,8 @@ impl ::core::fmt::Display for RCRule { } impl ::core::default::Default for RCRule { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; + let v: Vec = + vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; RCRule::new_unchecked(v.into()) } } @@ -836,9 +808,7 @@ impl molecule::prelude::Entity for RCRule { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .smt_root(self.smt_root()) - .flags(self.flags()) + Self::new_builder().smt_root(self.smt_root()).flags(self.flags()) } } #[derive(Clone, Copy)] @@ -928,8 +898,7 @@ impl molecule::prelude::Builder for RCRuleBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); RCRule::new_unchecked(inner.into()) } } @@ -1145,8 +1114,7 @@ impl molecule::prelude::Builder for RCCellVecBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); RCCellVec::new_unchecked(inner.into()) } } @@ -1225,8 +1193,8 @@ impl ::core::fmt::Display for RCData { impl ::core::default::Default for RCData { fn default() -> Self { let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, ]; RCData::new_unchecked(v.into()) } @@ -1362,8 +1330,7 @@ impl molecule::prelude::Builder for RCDataBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); RCData::new_unchecked(inner.into()) } } @@ -1702,8 +1669,7 @@ impl molecule::prelude::Builder for SmtProofBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtProof::new_unchecked(inner.into()) } } @@ -1967,9 +1933,7 @@ impl molecule::prelude::Builder for SmtProofEntryBuilder { type Entity = SmtProofEntry; const NAME: &'static str = "SmtProofEntryBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.mask.as_slice().len() - + self.proof.as_slice().len() + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.mask.as_slice().len() + self.proof.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); @@ -1988,8 +1952,7 @@ impl molecule::prelude::Builder for SmtProofEntryBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtProofEntry::new_unchecked(inner.into()) } } @@ -2185,12 +2148,7 @@ impl<'r> molecule::prelude::Reader<'r> for SmtProofEntryVecReader<'r> { return Ok(()); } if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!( - Self, - TotalSizeNotMatch, - molecule::NUMBER_SIZE * 2, - slice_len - ); + return ve!(Self, TotalSizeNotMatch, molecule::NUMBER_SIZE * 2, slice_len); } let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { @@ -2237,25 +2195,15 @@ impl molecule::prelude::Builder for SmtProofEntryVecBuilder { type Entity = SmtProofEntryVec; const NAME: &'static str = "SmtProofEntryVecBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (self.0.len() + 1) - + self - .0 - .iter() - .map(|inner| inner.as_slice().len()) - .sum::() + molecule::NUMBER_SIZE * (self.0.len() + 1) + self.0.iter().map(|inner| inner.as_slice().len()).sum::() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let item_count = self.0.len(); if item_count == 0 { - writer.write_all(&molecule::pack_number( - molecule::NUMBER_SIZE as molecule::Number, - ))?; + writer.write_all(&molecule::pack_number(molecule::NUMBER_SIZE as molecule::Number))?; } else { let (total_size, offsets) = self.0.iter().fold( - ( - molecule::NUMBER_SIZE * (item_count + 1), - Vec::with_capacity(item_count), - ), + (molecule::NUMBER_SIZE * (item_count + 1), Vec::with_capacity(item_count)), |(start, mut offsets), inner| { offsets.push(start); (start + inner.as_slice().len(), offsets) @@ -2273,8 +2221,7 @@ impl molecule::prelude::Builder for SmtProofEntryVecBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtProofEntryVec::new_unchecked(inner.into()) } } @@ -2353,10 +2300,8 @@ impl ::core::fmt::Display for SmtUpdateItem { } impl ::core::default::Default for SmtUpdateItem { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; + let v: Vec = + vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; SmtUpdateItem::new_unchecked(v.into()) } } @@ -2396,9 +2341,7 @@ impl molecule::prelude::Entity for SmtUpdateItem { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .key(self.key()) - .packed_values(self.packed_values()) + Self::new_builder().key(self.key()).packed_values(self.packed_values()) } } #[derive(Clone, Copy)] @@ -2488,8 +2431,7 @@ impl molecule::prelude::Builder for SmtUpdateItemBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtUpdateItem::new_unchecked(inner.into()) } } @@ -2705,8 +2647,7 @@ impl molecule::prelude::Builder for SmtUpdateItemVecBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtUpdateItemVec::new_unchecked(inner.into()) } } @@ -2789,9 +2730,7 @@ impl ::core::fmt::Display for SmtUpdateAction { } impl ::core::default::Default for SmtUpdateAction { fn default() -> Self { - let v: Vec = vec![ - 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + let v: Vec = vec![20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; SmtUpdateAction::new_unchecked(v.into()) } } @@ -2855,9 +2794,7 @@ impl molecule::prelude::Entity for SmtUpdateAction { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .updates(self.updates()) - .proof(self.proof()) + Self::new_builder().updates(self.updates()).proof(self.proof()) } } #[derive(Clone, Copy)] @@ -2997,9 +2934,7 @@ impl molecule::prelude::Builder for SmtUpdateActionBuilder { type Entity = SmtUpdateAction; const NAME: &'static str = "SmtUpdateActionBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.updates.as_slice().len() - + self.proof.as_slice().len() + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.updates.as_slice().len() + self.proof.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); @@ -3018,8 +2953,7 @@ impl molecule::prelude::Builder for SmtUpdateActionBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); SmtUpdateAction::new_unchecked(inner.into()) } } @@ -3053,9 +2987,7 @@ impl ::core::fmt::Display for XudtData { } impl ::core::default::Default for XudtData { fn default() -> Self { - let v: Vec = vec![ - 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, - ]; + let v: Vec = vec![20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0]; XudtData::new_unchecked(v.into()) } } @@ -3259,9 +3191,7 @@ impl molecule::prelude::Builder for XudtDataBuilder { type Entity = XudtData; const NAME: &'static str = "XudtDataBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.lock.as_slice().len() - + self.data.as_slice().len() + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.lock.as_slice().len() + self.data.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); @@ -3280,8 +3210,7 @@ impl molecule::prelude::Builder for XudtDataBuilder { } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + self.write(&mut inner).unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); XudtData::new_unchecked(inner.into()) } } diff --git a/tests/omni_lock_rust/tests/misc.rs b/tests/omni_lock_rust/tests/misc.rs index 6454416..97f3162 100644 --- a/tests/omni_lock_rust/tests/misc.rs +++ b/tests/omni_lock_rust/tests/misc.rs @@ -1,3 +1,4 @@ +use omni_lock_test::schemas::top_level::WitnessLayout; use openssl::hash::MessageDigest; use openssl::pkey::{PKey, Private, Public}; use openssl::rsa::Rsa; @@ -6,31 +7,25 @@ use sha3::{Digest, Keccak256}; use std::collections::HashMap; use std::convert::TryInto; -use ckb_chain_spec::consensus::{Consensus, ConsensusBuilder}; use ckb_crypto::secp::{Generator, Privkey, Pubkey}; use ckb_error::Error; use ckb_hash::{Blake2b, Blake2bBuilder}; use ckb_script::TxVerifyEnv; -use ckb_traits::{CellDataProvider, HeaderProvider}; +use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; use ckb_types::bytes::{BufMut, BytesMut}; use ckb_types::{ bytes::Bytes, core::{ cell::{CellMeta, CellMetaBuilder, ResolvedTransaction}, - hardfork::HardForkSwitch, - Capacity, DepType, EpochNumberWithFraction, HeaderView, ScriptHashType, TransactionBuilder, - TransactionView, + Capacity, DepType, EpochNumberWithFraction, HeaderView, ScriptHashType, TransactionBuilder, TransactionView, }, molecule, - packed::{ - self, Byte32, CellDep, CellInput, CellOutput, OutPoint, Script, WitnessArgs, - WitnessArgsBuilder, - }, + packed::{self, Byte32, CellDep, CellInput, CellOutput, OutPoint, Script, WitnessArgs, WitnessArgsBuilder}, prelude::*, H256 as CkbH256, }; use lazy_static::lazy_static; -use rand::prelude::{thread_rng, ThreadRng}; +use rand::prelude::thread_rng; use rand::seq::SliceRandom; use rand::Rng; use rand::RngCore; @@ -39,12 +34,18 @@ use sparse_merkle_tree::default_store::DefaultStore; use sparse_merkle_tree::traits::Hasher; use sparse_merkle_tree::{SparseMerkleTree, H256}; +use ckb_chain_spec::consensus::ConsensusBuilder; +use ckb_script::TransactionScriptsVerifier; +use ckb_types::core::hardfork::HardForks; +use ed25519_dalek::SigningKey; use omni_lock_test::omni_lock; use omni_lock_test::omni_lock::OmniLockWitnessLock; +use omni_lock_test::schemas::basic::{Message, SighashAll, SighashAllOnly}; use omni_lock_test::xudt_rce_mol::{ - RCCellVecBuilder, RCDataBuilder, RCDataUnion, RCRuleBuilder, SmtProofBuilder, - SmtProofEntryBuilder, SmtProofEntryVec, SmtProofEntryVecBuilder, + RCCellVecBuilder, RCDataBuilder, RCDataUnion, RCRuleBuilder, SmtProofBuilder, SmtProofEntryBuilder, + SmtProofEntryVec, SmtProofEntryVecBuilder, }; +use std::sync::Arc; // on(1): white list // off(0): black list @@ -75,13 +76,23 @@ pub const ERROR_NO_WHITE_LIST: i8 = 83; pub const ERROR_ON_BLACK_LIST: i8 = 57; pub const ERROR_RCE_EMERGENCY_HALT: i8 = 54; pub const ERROR_RSA_VERIFY_FAILED: i8 = 42; +pub const ERROR_INCORRECT_SINCE_FLAGS: i8 = -23; pub const ERROR_INCORRECT_SINCE_VALUE: i8 = -24; pub const ERROR_ISO97962_INVALID_ARG9: i8 = 61; +pub const ERROR_MOL2_ERR_OVERFLOW: i8 = 8; // sudt supply errors pub const ERROR_EXCEED_SUPPLY: i8 = 90; pub const ERROR_SUPPLY_AMOUNT: i8 = 91; pub const ERROR_BURN: i8 = 92; pub const ERROR_NO_INFO_CELL: i8 = 93; +// cobuild +pub const ERROR_COBUILD_MOL2_ERR_DATA: i8 = 0x07; +pub const ERROR_SIGHASHALL_DUP: i8 = 113; +pub const MOL2_ERR_OVERFLOW: i8 = 8; // parse witnesses error + +pub const ERROR_IDENTITY_WRONG_ARGS: i8 = 71; +pub const ERROR_MISMATCHED: i8 = 73; +pub const ERROR_ARGS_FORMAT: i8 = 87; // https://github.com/bitcoin-core/secp256k1/blob/d373bf6d08c82ac5496bf8103698c9f54d8d99d2/include/secp256k1.h#L219 pub const SECP256K1_TAG_PUBKEY_EVEN: u8 = 0x02; @@ -104,31 +115,20 @@ pub const COMMON_PREFIX: &str = "CKB transaction: 0x"; lazy_static! { pub static ref OMNI_LOCK: Bytes = Bytes::from(&include_bytes!("../../../build/omni_lock")[..]); - pub static ref SIMPLE_UDT: Bytes = - Bytes::from(&include_bytes!("../../../build/simple_udt")[..]); - pub static ref SECP256K1_DATA_BIN: Bytes = - Bytes::from(&include_bytes!("../../../build/secp256k1_data_20210801")[..]); - pub static ref ALWAYS_SUCCESS: Bytes = - Bytes::from(&include_bytes!("../../../build/always_success")[..]); + pub static ref SIMPLE_UDT: Bytes = Bytes::from(&include_bytes!("../../../build/simple_udt")[..]); + pub static ref ALWAYS_SUCCESS: Bytes = Bytes::from(&include_bytes!("../../../build/always_success")[..]); pub static ref VALIDATE_SIGNATURE_RSA: Bytes = Bytes::from(&include_bytes!("../../../build/validate_signature_rsa")[..]); - pub static ref SMT_EXISTING: H256 = H256::from([ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 - ]); - pub static ref SMT_NOT_EXISTING: H256 = H256::from([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 - ]); + pub static ref SMT_EXISTING: H256 = + H256::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + pub static ref SMT_NOT_EXISTING: H256 = + H256::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); } pub struct CKBBlake2bHasher(Blake2b); impl Default for CKBBlake2bHasher { fn default() -> Self { - let blake2b = Blake2bBuilder::new(BLAKE2B_LEN) - .personal(PERSONALIZATION) - .key(BLAKE2B_KEY) - .build(); + let blake2b = Blake2bBuilder::new(BLAKE2B_LEN).personal(PERSONALIZATION).key(BLAKE2B_KEY).build(); CKBBlake2bHasher(blake2b) } } @@ -157,15 +157,6 @@ pub fn new_smt(pairs: Vec<(H256, H256)>) -> SMT { smt } -pub fn gen_random_out_point(rng: &mut ThreadRng) -> OutPoint { - let hash = { - let mut buf = [0u8; 32]; - rng.fill(&mut buf); - Pack::pack(&buf) - }; - OutPoint::new(hash, 0) -} - // // deploy "bin" to cell, then build a script to point it. // @@ -194,11 +185,7 @@ fn build_script( let type_script_in_code = { if in_input_cell { let hash: Bytes = Bytes::copy_from_slice(&hash); - always_success - .clone() - .as_builder() - .args(hash.pack()) - .build() + always_success.clone().as_builder().args(hash.pack()).build() } else { // this args can be anything let args = vec![0u8; 32]; @@ -225,73 +212,38 @@ fn build_script( let tx_builder = if in_input_cell { let witness_args = WitnessArgsBuilder::default().build(); - tx_builder - .input(CellInput::new(out_point.clone(), 0)) - .witness(witness_args.as_bytes().pack()) + tx_builder.input(CellInput::new(out_point.clone(), 0)).witness(witness_args.as_bytes().pack()) } else { - tx_builder.cell_dep( - CellDep::new_builder() - .out_point(out_point.clone()) - .dep_type(DepType::Code.into()) - .build(), - ) + tx_builder.cell_dep(CellDep::new_builder().out_point(out_point.clone()).dep_type(DepType::Code.into()).build()) }; - let code_hash = if is_type { - ckb_hash::blake2b_256(type_script_in_code.as_slice()) - } else { - ckb_hash::blake2b_256(bin) - }; - let hash_type = if is_type { - ScriptHashType::Type - } else { - ScriptHashType::Data - }; + let code_hash = + if is_type { ckb_hash::blake2b_256(type_script_in_code.as_slice()) } else { ckb_hash::blake2b_256(bin) }; + let hash_type = if is_type { ScriptHashType::Type } else { ScriptHashType::Data1 }; - let script = Script::new_builder() - .args(args.pack()) - .code_hash(code_hash.pack()) - .hash_type(hash_type.into()) - .build(); + let script = + Script::new_builder().args(args.pack()).code_hash(code_hash.pack()).hash_type(hash_type.into()).build(); (tx_builder, script) } // return smt root and proof fn build_smt_on_bl(hashes: &Vec<[u8; 32]>, on: bool) -> (H256, Vec) { - let test_pairs: Vec<(H256, H256)> = hashes - .clone() - .into_iter() - .map(|hash| (hash.into(), SMT_NOT_EXISTING.clone())) - .collect(); + let test_pairs: Vec<(H256, H256)> = + hashes.clone().into_iter().map(|hash| (hash.into(), SMT_NOT_EXISTING.clone())).collect(); // this is the hash on black list, but "hashes" are not on that. - let key_on_bl1: H256 = [ - 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ] - .into(); - let key_on_bl2: H256 = [ - 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ] - .into(); - let pairs = vec![ - (key_on_bl1, SMT_EXISTING.clone()), - (key_on_bl2, SMT_EXISTING.clone()), - ]; + let key_on_bl1: H256 = + [111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into(); + let key_on_bl2: H256 = + [222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into(); + let pairs = vec![(key_on_bl1, SMT_EXISTING.clone()), (key_on_bl2, SMT_EXISTING.clone())]; let smt = new_smt(pairs.clone()); let root = smt.root(); - let proof = smt - .merkle_proof(test_pairs.clone().into_iter().map(|(k, _)| k).collect()) - .expect("gen proof"); - let compiled_proof = proof - .clone() - .compile(test_pairs.clone()) - .expect("compile proof"); - let test_on = compiled_proof - .verify::(smt.root(), test_pairs.clone()) - .expect("verify compiled proof"); + let proof = smt.merkle_proof(test_pairs.clone().into_iter().map(|(k, _)| k).collect()).expect("gen proof"); + let compiled_proof = proof.clone().compile(test_pairs.clone()).expect("compile proof"); + let test_on = + compiled_proof.verify::(smt.root(), test_pairs.clone()).expect("verify compiled proof"); assert!(test_on); if on { let mut new_root = root.clone(); @@ -309,27 +261,15 @@ fn build_smt_on_bl(hashes: &Vec<[u8; 32]>, on: bool) -> (H256, Vec) { // return smt root and proof fn build_smt_on_wl(hashes: &Vec<[u8; 32]>, on: bool) -> (H256, Vec) { - let existing_pairs: Vec<(H256, H256)> = hashes - .clone() - .into_iter() - .map(|hash| (hash.into(), SMT_EXISTING.clone())) - .collect(); + let existing_pairs: Vec<(H256, H256)> = + hashes.clone().into_iter().map(|hash| (hash.into(), SMT_EXISTING.clone())).collect(); // this is the hash on white list, and "hashes" are on that. - let key_on_wl1: H256 = [ - 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ] - .into(); - let key_on_wl2: H256 = [ - 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ] - .into(); - let mut pairs = vec![ - (key_on_wl1, SMT_EXISTING.clone()), - (key_on_wl2, SMT_EXISTING.clone()), - ]; + let key_on_wl1: H256 = + [111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into(); + let key_on_wl2: H256 = + [222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into(); + let mut pairs = vec![(key_on_wl1, SMT_EXISTING.clone()), (key_on_wl2, SMT_EXISTING.clone())]; if on { pairs.extend(existing_pairs.clone()); } @@ -337,16 +277,10 @@ fn build_smt_on_wl(hashes: &Vec<[u8; 32]>, on: bool) -> (H256, Vec) { let smt = new_smt(pairs); let root = smt.root(); - let proof = smt - .merkle_proof(existing_pairs.clone().into_iter().map(|(k, _)| k).collect()) - .expect("gen proof"); - let compiled_proof = proof - .clone() - .compile(existing_pairs.clone()) - .expect("compile proof"); - let test_on = compiled_proof - .verify::(root, existing_pairs.clone()) - .expect("verify compiled proof"); + let proof = smt.merkle_proof(existing_pairs.clone().into_iter().map(|(k, _)| k).collect()).expect("gen proof"); + let compiled_proof = proof.clone().compile(existing_pairs.clone()).expect("compile proof"); + let test_on = + compiled_proof.verify::(root, existing_pairs.clone()).expect("verify compiled proof"); if on { assert!(test_on); } else { @@ -364,17 +298,12 @@ fn build_rc_rule(smt_root: &[u8; 32], is_black: bool, is_emergency: bool) -> Byt if is_emergency { flags ^= EMERGENCY_HALT_MODE_MASK; } - let rcrule = RCRuleBuilder::default() - .flags(flags.into()) - .smt_root(smt_root.pack()) - .build(); - let res = RCDataBuilder::default() - .set(RCDataUnion::RCRule(rcrule)) - .build(); + let rcrule = RCRuleBuilder::default().flags(flags.into()).smt_root(smt_root.pack()).build(); + let res = RCDataBuilder::default().set(RCDataUnion::RCRule(rcrule)).build(); res.as_bytes() } -#[derive(Default)] +#[derive(Default, Clone)] pub struct DummyDataLoader { pub cells: HashMap, } @@ -388,16 +317,11 @@ impl DummyDataLoader { impl CellDataProvider for DummyDataLoader { // load Cell Data fn load_cell_data(&self, cell: &CellMeta) -> Option { - cell.mem_cell_data.clone().or_else(|| { - self.cells - .get(&cell.out_point) - .map(|(_, data)| data.clone()) - }) + cell.mem_cell_data.clone().or_else(|| self.cells.get(&cell.out_point).map(|(_, data)| data.clone())) } fn load_cell_data_hash(&self, cell: &CellMeta) -> Option { - self.load_cell_data(cell) - .map(|e| CellOutput::calc_data_hash(&e)) + self.load_cell_data(cell).map(|e| CellOutput::calc_data_hash(&e)) } fn get_cell_data(&self, _out_point: &OutPoint) -> Option { @@ -415,6 +339,12 @@ impl HeaderProvider for DummyDataLoader { } } +impl ExtensionProvider for DummyDataLoader { + fn get_block_extension(&self, _hash: &packed::Byte32) -> Option { + None + } +} + pub fn blake160(message: &[u8]) -> Bytes { let r = ckb_hash::blake2b_256(message); Bytes::copy_from_slice(&r[..20]) @@ -436,19 +366,12 @@ pub fn convert_keccak256_hash(message: &[u8]) -> CkbH256 { CkbH256::from_slice(r.as_slice()).expect("convert_keccak256_hash") } -pub fn sign_tx( - dummy: &mut DummyDataLoader, - tx: TransactionView, - config: &mut TestConfig, -) -> TransactionView { +pub fn sign_tx(dummy: &mut DummyDataLoader, tx: TransactionView, config: &mut TestConfig) -> TransactionView { // for owner lock, the first input is an "always success" script: used as owner lock let (begin_index, witnesses_len) = if config.is_owner_lock() { (1, tx.witnesses().len() - 1) } else { - ( - config.leading_witness_count, - tx.witnesses().len() - config.leading_witness_count, - ) + (config.leading_witness_count, tx.witnesses().len() - config.leading_witness_count) }; sign_tx_by_input_group(dummy, tx, begin_index, witnesses_len, config) } @@ -459,15 +382,10 @@ fn build_proofs(proofs: Vec>, proof_masks: Vec) -> SmtProofEntryVec let mut builder = SmtProofEntryVecBuilder::default(); let iter = proofs.iter().zip(proof_masks.iter()); for (p, m) in iter { - let proof_builder = SmtProofBuilder::default().set( - p.into_iter() - .map(|v| molecule::prelude::Byte::new(*v)) - .collect(), - ); + let proof_builder = + SmtProofBuilder::default().set(p.into_iter().map(|v| molecule::prelude::Byte::new(*v)).collect()); - let temp = SmtProofEntryBuilder::default() - .proof(proof_builder.build()) - .mask((*m).into()); + let temp = SmtProofEntryBuilder::default().proof(proof_builder.build()).mask((*m).into()); builder = builder.push(temp.build()); } builder.build() @@ -475,10 +393,7 @@ fn build_proofs(proofs: Vec>, proof_masks: Vec) -> SmtProofEntryVec pub fn build_always_success_script() -> Script { let data_hash = CellOutput::calc_data_hash(&ALWAYS_SUCCESS); - Script::new_builder() - .code_hash(data_hash.clone()) - .hash_type(ScriptHashType::Data.into()) - .build() + Script::new_builder().code_hash(data_hash.clone()).hash_type(ScriptHashType::Data1.into()).build() } pub fn build_omni_lock_script(config: &mut TestConfig, args: Bytes) -> Script { @@ -504,7 +419,7 @@ pub fn build_omni_lock_script(config: &mut TestConfig, args: Bytes) -> Script { Script::new_builder() .args(args.pack()) .code_hash(sighash_all_cell_data_hash.clone()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data1.into()) .build() } @@ -515,7 +430,7 @@ pub fn append_rc( ) -> TransactionBuilder { let smt_key = config.id.to_smt_key(); let (proofs, rc_datas, proof_masks) = generate_proofs(config.scheme, &vec![smt_key]); - let (rc_root, b0) = generate_rce_cell(dummy, tx_builder, rc_datas, config.smt_in_input); + let (rc_root, b0) = generate_rce_cell(dummy, tx_builder, rc_datas, config.smt_in_input, config); config.proofs = proofs; config.proof_masks = proof_masks; @@ -532,11 +447,14 @@ pub fn append_rc( pub fn append_input_lock_script_hash( dummy: &mut DummyDataLoader, tx_builder: TransactionBuilder, + config: &TestConfig, ) -> (TransactionBuilder, Bytes) { let mut rng = thread_rng(); let previous_tx_hash = { - let mut buf = [0u8; 32]; - rng.fill(&mut buf); + let mut buf = [3u8; 32]; + if config.random_tx { + rng.fill(&mut buf); + } buf.pack() }; let previous_out_point = OutPoint::new(previous_tx_hash, 0); @@ -545,7 +463,7 @@ pub fn append_input_lock_script_hash( let script = Script::new_builder() .args(Default::default()) .code_hash(hash.clone()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data1.into()) .build(); let blake160 = { let hash = script.calc_script_hash(); @@ -554,17 +472,9 @@ pub fn append_input_lock_script_hash( res.freeze() }; - let previous_output_cell = CellOutput::new_builder() - .capacity(Capacity::shannons(42).pack()) - .lock(script) - .build(); - dummy.cells.insert( - previous_out_point.clone(), - (previous_output_cell.clone(), Bytes::new()), - ); - let tx_builder = tx_builder - .input(CellInput::new(previous_out_point, 0)) - .witness(Default::default()); + let previous_output_cell = CellOutput::new_builder().capacity(Capacity::shannons(42).pack()).lock(script).build(); + dummy.cells.insert(previous_out_point.clone(), (previous_output_cell.clone(), Bytes::new())); + let tx_builder = tx_builder.input(CellInput::new(previous_out_point, 0)).witness(Default::default()); (tx_builder, blake160) } @@ -585,10 +495,7 @@ pub fn write_back_preimage_hash(dummy: &mut DummyDataLoader, flags: u8, hash: By if raw[0] == flags { let mut new_args = Vec::from(raw.as_ref()); new_args[1..21].copy_from_slice(hash.as_ref()); - let new_script = script - .as_builder() - .args(Bytes::from(new_args).pack()) - .build(); + let new_script = script.as_builder().args(Bytes::from(new_args).pack()).build(); cell = cell.as_builder().lock(new_script).build(); } } @@ -609,57 +516,50 @@ pub fn sign_tx_by_input_group( let tx_hash = tx.hash(); let mut preimage_hash: Bytes = Default::default(); + let message = if config.cobuild_enabled { + cobuild_generate_signing_message_hash(&config.cobuild_message, dummy, &tx) + } else { + let mut blake2b = ckb_hash::new_blake2b(); + let mut message = [0u8; 32]; + blake2b.update(&tx_hash.raw_data()); + // digest the first witness + let witness = WitnessArgs::new_unchecked(tx.witnesses().get(begin_index).unwrap().unpack()); + let zero_lock = gen_zero_witness_lock( + config.use_rc, + config.use_rc_identity, + &proof_vec, + &identity, + config.sig_len, + config.preimage_len, + ); + + let witness_for_digest = witness.clone().as_builder().lock(Some(zero_lock).pack()).build(); + let witness_len = witness_for_digest.as_bytes().len() as u64; + blake2b.update(&witness_len.to_le_bytes()); + blake2b.update(&witness_for_digest.as_bytes()); + ((begin_index + 1)..(begin_index + len)).for_each(|n| { + let witness = tx.witnesses().get(n).unwrap(); + let witness_len = witness.raw_data().len() as u64; + blake2b.update(&witness_len.to_le_bytes()); + blake2b.update(&witness.raw_data()); + }); + blake2b.finalize(&mut message); + message + }; + println!("origin message: {:02x?}", message); let mut signed_witnesses: Vec = tx .inputs() .into_iter() .enumerate() .map(|(i, _)| { if i == begin_index { - let mut blake2b = ckb_hash::new_blake2b(); - let mut message = [0u8; 32]; - blake2b.update(&tx_hash.raw_data()); - // digest the first witness - let witness = WitnessArgs::new_unchecked(tx.witnesses().get(i).unwrap().unpack()); - let zero_lock = gen_zero_witness_lock( - config.use_rc, - config.use_rc_identity, - &proof_vec, - &identity, - config.sig_len, - config.preimage_len, - ); - - let witness_for_digest = witness - .clone() - .as_builder() - .lock(Some(zero_lock).pack()) - .build(); - let witness_len = witness_for_digest.as_bytes().len() as u64; - blake2b.update(&witness_len.to_le_bytes()); - blake2b.update(&witness_for_digest.as_bytes()); - ((i + 1)..(i + len)).for_each(|n| { - let witness = tx.witnesses().get(n).unwrap(); - let witness_len = witness.raw_data().len() as u64; - blake2b.update(&witness_len.to_le_bytes()); - blake2b.update(&witness.raw_data()); - }); - blake2b.finalize(&mut message); - - println!("origin message: {:02x?}", message); - - let message = if use_chain_confg(config.id.flags) { + let message = if use_chain_config(config.id.flags) { assert!(config.chain_config.is_some()); - config - .chain_config - .as_ref() - .unwrap() - .convert_message(&message) + config.chain_config.as_ref().unwrap().convert_message(&message) } else { CkbH256::from(message) }; - println!("sign message: {:02x?}", message.as_bytes().to_vec()); - let witness_lock = if config.id.flags == IDENTITY_FLAGS_DL { let (mut sig, pubkey) = if config.use_rsa { rsa_sign(message.as_bytes(), &config.rsa_private_key) @@ -677,7 +577,7 @@ pub fn sign_tx_by_input_group( sig = wrong_sig; } let hash = blake160(pubkey.as_ref()); - let preimage = gen_exec_preimage(&config.rsa_script, &hash); + let preimage = gen_dl_preimage(&config.rsa_script, &hash); preimage_hash = blake160(preimage.as_ref()); let sig_bytes = Bytes::from(sig); @@ -689,60 +589,120 @@ pub fn sign_tx_by_input_group( &identity, Some(preimage), ) - } else if config.id.flags == IDENTITY_FLAGS_MULTISIG { - let sig = config.multisig.sign(&message.into()); - gen_witness_lock( - sig, - config.use_rc, - config.use_rc_identity, - &proof_vec, - &identity, - None, - ) - } else if use_chain_confg(config.id.flags) { - let sig_bytes = config - .chain_config - .as_ref() - .unwrap() - .sign(&config.private_key, message); - println!( - "bitcoin sign(size: {}): {:02x?}", - sig_bytes.len(), - sig_bytes.to_vec() - ); + } else if config.id.flags == IDENTITY_FLAGS_EXEC { + let script = build_always_success_script(); + // always success script is used here. Anything is OK. + let hash = blake160(&[0u8; 20]); + let preimage = gen_exec_preimage(&script, &hash); + preimage_hash = blake160(preimage.as_ref()); + + let sig_bytes = Bytes::from(vec![0u8; 65]); gen_witness_lock( sig_bytes, config.use_rc, config.use_rc_identity, &proof_vec, &identity, - None, + Some(preimage), ) + } else if config.id.flags == IDENTITY_FLAGS_MULTISIG { + let sig = config.multisig.sign(&message.into()); + gen_witness_lock(sig, config.use_rc, config.use_rc_identity, &proof_vec, &identity, None) + } else if config.id.flags == IDENTITY_FLAGS_SOLANA { + if let Some(sig) = config.solana_phantom_sig.clone() { + let sig_plus_pubkey: Bytes = sig.into(); + gen_witness_lock( + sig_plus_pubkey, + config.use_rc, + config.use_rc_identity, + &proof_vec, + &identity, + None, + ) + } else { + // name conflicted + use ed25519_dalek::Signer; + // solana has different signing process and algorithm + let signing_key = SigningKey::from_bytes(&config.solana_secret_key); + let msg = String::from("CKB transaction: 0x") + &hex::encode(message); + println!("message to be signed by ed25519: {}", msg); + let sig = signing_key.sign(msg.as_bytes()); + let verifying_key = signing_key.verifying_key(); + + let mut sig_plus_pubkey = sig.to_vec(); + match config.scheme { + TestScheme::SolanaWrongSignature => { + sig_plus_pubkey[0] ^= 1; + } + _ => {} + } + sig_plus_pubkey.extend(verifying_key.to_bytes()); + match config.scheme { + TestScheme::SolanaWrongPubkey => { + sig_plus_pubkey[64] ^= 1; + } + _ => {} + } + let sig_plus_pubkey: Bytes = sig_plus_pubkey.into(); + gen_witness_lock( + sig_plus_pubkey, + config.use_rc, + config.use_rc_identity, + &proof_vec, + &identity, + None, + ) + } + } else if use_chain_config(config.id.flags) { + let sig_bytes = config.chain_config.as_ref().unwrap().sign(&config.private_key, message); + println!("bitcoin sign(size: {}): {:02x?}", sig_bytes.len(), sig_bytes.to_vec()); + gen_witness_lock(sig_bytes, config.use_rc, config.use_rc_identity, &proof_vec, &identity, None) } else { let sig = config.private_key.sign_recoverable(&message).expect("sign"); let sig_bytes = Bytes::from(sig.serialize()); - gen_witness_lock( - sig_bytes, - config.use_rc, - config.use_rc_identity, - &proof_vec, - &identity, - None, - ) + gen_witness_lock(sig_bytes, config.use_rc, config.use_rc_identity, &proof_vec, &identity, None) }; - println!( - "omni lock witness(size: {}): {:02x?}", - witness_lock.len(), - witness_lock.to_vec() - ); - - witness - .as_builder() - .lock(Some(witness_lock).pack()) - .build() - .as_bytes() - .pack() + println!("omni lock witness(size: {}): {:02x?}", witness_lock.len(), witness_lock.to_vec()); + + if config.cobuild_enabled { + match &config.cobuild_message { + Some(msg) => { + let sighash_all = SighashAll::new_builder() + .message(msg.clone()) + .seal([Bytes::copy_from_slice(&[0x00u8]), witness_lock].concat().pack()) + .build(); + let sighash_all = WitnessLayout::new_builder().set(sighash_all).build(); + let sighash_all = sighash_all.as_bytes(); + // println!( + // "sighash_all with enum id(size: {}): {:02x?}", + // sighash_all.len(), + // sighash_all.as_ref() + // ); + let res = sighash_all.pack(); + // println!("res(size: {}): {:02x?}", res.len(), res.as_bytes().as_ref()); + res + } + None => { + let sighash_all_only = SighashAllOnly::new_builder() + .seal([Bytes::copy_from_slice(&[0x00u8]), witness_lock].concat().pack()) + .build(); + let sighash_all_only = WitnessLayout::new_builder().set(sighash_all_only).build(); + let sighash_all_only = sighash_all_only.as_bytes(); + // println!( + // "sighash_all_only with enum id(size: {}): {:02x?}", + // sighash_all_only.len(), + // sighash_all_only.as_ref() + // ); + let res = sighash_all_only.pack(); + // println!("res(size: {}): {:02x?}", res.len(), res.as_bytes().as_ref()); + res + } + } + } else { + let witness = WitnessArgs::new_unchecked(tx.witnesses().get(begin_index).unwrap().unpack()); + witness.as_builder().lock(Some(witness_lock).pack()).build().as_bytes().pack() + } } else { tx.witnesses().get(i).unwrap_or_default() } @@ -751,25 +711,32 @@ pub fn sign_tx_by_input_group( for i in signed_witnesses.len()..tx.witnesses().len() { signed_witnesses.push(tx.witnesses().get(i).unwrap()); } - if config.scheme2 == TestScheme2::NoWitness { - signed_witnesses.clear(); - } if preimage_hash.len() == 20 { - write_back_preimage_hash(dummy, IDENTITY_FLAGS_DL, preimage_hash); + if config.id.flags == IDENTITY_FLAGS_DL { + write_back_preimage_hash(dummy, IDENTITY_FLAGS_DL, preimage_hash); + } else if config.id.flags == IDENTITY_FLAGS_EXEC { + write_back_preimage_hash(dummy, IDENTITY_FLAGS_EXEC, preimage_hash); + } else { + panic!("preimage_hash"); + } } + + match &config.custom_extension_witnesses_beginning { + Some(ws) => { + let mut ws: Vec = ws.iter().map(|f| f.pack()).collect(); + ws.extend_from_slice(&signed_witnesses); + signed_witnesses = ws; + } + _ => {} + } + // calculate message - tx.as_advanced_builder() - .set_witnesses(signed_witnesses) - .build() + tx.as_advanced_builder().set_witnesses(signed_witnesses).build() } pub fn gen_tx(dummy: &mut DummyDataLoader, config: &mut TestConfig) -> TransactionView { let lock_args = config.gen_args(); - println!( - "omni lock args(size: {}): {:02x?}", - lock_args.len(), - lock_args.to_vec() - ); + println!("omni lock args(size: {}): {:02x?}", lock_args.len(), lock_args.to_vec()); gen_tx_with_grouped_args(dummy, vec![(lock_args, 1)], config) } @@ -782,108 +749,50 @@ pub fn gen_tx_with_grouped_args( // setup sighash_all dep let sighash_all_out_point = { let contract_tx_hash = { - let mut buf = [0u8; 32]; - rng.fill(&mut buf); + let mut buf = [1u8; 32]; + if config.random_tx { + rng.fill(&mut buf); + } buf.pack() }; OutPoint::new(contract_tx_hash.clone(), 0) }; // dep contract code - let sighash_all_cell = CellOutput::new_builder() - .capacity( - Capacity::bytes(OMNI_LOCK.len()) - .expect("script capacity") - .pack(), - ) - .build(); + let sighash_all_cell = + CellOutput::new_builder().capacity(Capacity::bytes(OMNI_LOCK.len()).expect("script capacity").pack()).build(); let sighash_all_cell_data_hash = CellOutput::calc_data_hash(&OMNI_LOCK); - dummy.cells.insert( - sighash_all_out_point.clone(), - (sighash_all_cell, OMNI_LOCK.clone()), - ); + dummy.cells.insert(sighash_all_out_point.clone(), (sighash_all_cell, OMNI_LOCK.clone())); // always success let always_success_out_point = { let contract_tx_hash = { - let mut buf = [0u8; 32]; - rng.fill(&mut buf); + let mut buf = [2u8; 32]; + if config.random_tx { + rng.fill(&mut buf); + } buf.pack() }; OutPoint::new(contract_tx_hash.clone(), 0) }; let always_success_cell = CellOutput::new_builder() - .capacity( - Capacity::bytes(ALWAYS_SUCCESS.len()) - .expect("script capacity") - .pack(), - ) - .build(); - dummy.cells.insert( - always_success_out_point.clone(), - (always_success_cell, ALWAYS_SUCCESS.clone()), - ); - // setup secp256k1_data dep - let secp256k1_data_out_point = { - let tx_hash = { - let mut buf = [0u8; 32]; - rng.fill(&mut buf); - buf.pack() - }; - OutPoint::new(tx_hash, 0) - }; - let secp256k1_data_cell = CellOutput::new_builder() - .capacity( - Capacity::bytes(SECP256K1_DATA_BIN.len()) - .expect("data capacity") - .pack(), - ) + .capacity(Capacity::bytes(ALWAYS_SUCCESS.len()).expect("script capacity").pack()) .build(); - dummy.cells.insert( - secp256k1_data_out_point.clone(), - (secp256k1_data_cell, SECP256K1_DATA_BIN.clone()), - ); + dummy.cells.insert(always_success_out_point.clone(), (always_success_cell, ALWAYS_SUCCESS.clone())); // setup default tx builder let dummy_capacity = Capacity::shannons(42); let mut tx_builder = TransactionBuilder::default() - .cell_dep( - CellDep::new_builder() - .out_point(sighash_all_out_point) - .dep_type(DepType::Code.into()) - .build(), - ) - .cell_dep( - CellDep::new_builder() - .out_point(always_success_out_point) - .dep_type(DepType::Code.into()) - .build(), - ) - .cell_dep( - CellDep::new_builder() - .out_point(secp256k1_data_out_point) - .dep_type(DepType::Code.into()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(dummy_capacity.pack()) - .build(), - ) + .cell_dep(CellDep::new_builder().out_point(sighash_all_out_point).dep_type(DepType::Code.into()).build()) + .cell_dep(CellDep::new_builder().out_point(always_success_out_point).dep_type(DepType::Code.into()).build()) + .output(CellOutput::new_builder().capacity(dummy_capacity.pack()).build()) .output_data(Bytes::new().pack()); // validate_signature_rsa will be referenced by preimage in witness - let (b0, rsa_script) = build_script( - dummy, - tx_builder, - false, - false, - &VALIDATE_SIGNATURE_RSA, - Default::default(), - ); + let (b0, rsa_script) = build_script(dummy, tx_builder, false, false, &VALIDATE_SIGNATURE_RSA, Default::default()); tx_builder = b0; config.rsa_script = rsa_script; if config.is_owner_lock() { // insert an "always success" script as first input script. - let (b0, blake160) = append_input_lock_script_hash(dummy, tx_builder); + let (b0, blake160) = append_input_lock_script_hash(dummy, tx_builder, &config); tx_builder = b0; config.id.blake160 = blake160; } @@ -896,7 +805,9 @@ pub fn gen_tx_with_grouped_args( for _ in 0..inputs_size { let previous_tx_hash = { let mut buf = [0u8; 32]; - rng.fill(&mut buf); + if config.random_tx { + rng.fill(&mut buf); + } buf.pack() }; args = if config.is_owner_lock() { @@ -921,40 +832,35 @@ pub fn gen_tx_with_grouped_args( let script = Script::new_builder() .args(args.pack()) .code_hash(sighash_all_cell_data_hash.clone()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data1.into()) .build(); config.running_script = script.clone(); - let previous_output_cell = CellOutput::new_builder() - .capacity(dummy_capacity.pack()) - .lock(script) - .build(); - dummy.cells.insert( - previous_out_point.clone(), - (previous_output_cell.clone(), Bytes::new()), - ); + let previous_output_cell = CellOutput::new_builder().capacity(dummy_capacity.pack()).lock(script).build(); + dummy.cells.insert(previous_out_point.clone(), (previous_output_cell.clone(), Bytes::new())); let mut random_extra_witness = Vec::::new(); - let witness_len = if config.scheme == TestScheme::LongWitness { - 40000 - } else { - 32 - }; + let witness_len = if config.scheme == TestScheme::LongWitness { 40000 } else { 32 }; random_extra_witness.resize(witness_len, 0); - rng.fill(&mut random_extra_witness[..]); + if config.random_tx { + rng.fill(&mut random_extra_witness[..]); + } let witness_args = WitnessArgsBuilder::default() .input_type(Some(Bytes::copy_from_slice(&random_extra_witness[..])).pack()) .build(); - let since = if config.use_since { - config.input_since - } else { - 0 - }; - tx_builder = tx_builder - .input(CellInput::new(previous_out_point, since)) - .witness(witness_args.as_bytes().pack()); + let since = if config.use_since { config.input_since } else { 0 }; + tx_builder = + tx_builder.input(CellInput::new(previous_out_point, since)).witness(witness_args.as_bytes().pack()); } } + match &config.custom_extension_witnesses { + Some(ws) => { + for w in ws { + tx_builder = tx_builder.witness(w.pack()); + } + } + _ => {} + }; tx_builder.build() } @@ -976,25 +882,17 @@ pub fn sign_tx_hash(tx: TransactionView, tx_hash: &[u8], config: &TestConfig) -> &identity, Default::default(), ); - let witness_args = WitnessArgsBuilder::default() - .lock(Some(witness_lock).pack()) - .build(); - tx.as_advanced_builder() - .set_witnesses(vec![witness_args.as_bytes().pack()]) - .build() + let witness_args = WitnessArgsBuilder::default().lock(Some(witness_lock).pack()).build(); + tx.as_advanced_builder().set_witnesses(vec![witness_args.as_bytes().pack()]).build() } -pub fn build_resolved_tx( - data_loader: &DummyDataLoader, - tx: &TransactionView, -) -> ResolvedTransaction { +pub fn build_resolved_tx(data_loader: &DummyDataLoader, tx: &TransactionView) -> ResolvedTransaction { let resolved_cell_deps = tx .cell_deps() .into_iter() .map(|dep| { let deps_out_point = dep.clone(); - let (dep_output, dep_data) = - data_loader.cells.get(&deps_out_point.out_point()).unwrap(); + let (dep_output, dep_data) = data_loader.cells.get(&deps_out_point.out_point()).unwrap(); CellMetaBuilder::from_cell_output(dep_output.to_owned(), dep_data.to_owned()) .out_point(deps_out_point.out_point().clone()) .build() @@ -1012,20 +910,12 @@ pub fn build_resolved_tx( ); } - ResolvedTransaction { - transaction: tx.clone(), - resolved_cell_deps, - resolved_inputs, - resolved_dep_groups: vec![], - } + ResolvedTransaction { transaction: tx.clone(), resolved_cell_deps, resolved_inputs, resolved_dep_groups: vec![] } } pub fn debug_printer(script: &Byte32, msg: &str) { let slice = script.as_slice(); - let str = format!( - "Script({:x}{:x}{:x}{:x}{:x})", - slice[0], slice[1], slice[2], slice[3], slice[4] - ); + let str = format!("Script({:x}{:x}{:x}{:x}{:x})", slice[0], slice[1], slice[2], slice[3], slice[4]); println!("{:?}: {}", str, msg); } @@ -1037,6 +927,7 @@ pub const IDENTITY_FLAGS_BITCOIN: u8 = 4; pub const IDENTITY_FLAGS_DOGECOIN: u8 = 5; pub const IDENTITY_FLAGS_MULTISIG: u8 = 6; pub const IDENTITY_FLAGS_ETHEREUM_DISPLAYING: u8 = 18; +pub const IDENTITY_FLAGS_SOLANA: u8 = 19; pub const IDENTITY_FLAGS_OWNER_LOCK: u8 = 0xFC; pub const IDENTITY_FLAGS_EXEC: u8 = 0xFD; @@ -1132,10 +1023,7 @@ impl MultisigTestConfig { pub fn gen_identity(&self) -> Identity { let script = self.gen_multisig_script(); - Identity { - flags: IDENTITY_FLAGS_MULTISIG, - blake160: blake160(&script), - } + Identity { flags: IDENTITY_FLAGS_MULTISIG, blake160: blake160(&script) } } } @@ -1157,7 +1045,7 @@ pub trait ChainConfig { fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes; } -pub fn use_chain_confg(flags: u8) -> bool { +pub fn use_chain_config(flags: u8) -> bool { flags == IDENTITY_FLAGS_ETHEREUM || flags == IDENTITY_FLAGS_EOS || flags == IDENTITY_FLAGS_TRON @@ -1201,10 +1089,7 @@ impl ChainConfig for EthereumDisplayConfig { let mut hasher = Keccak256::new(); hasher.update(eth_prefix); - hasher.update(Bytes::from(format!( - "{}", - COMMON_PREFIX.len() + message.len() * 2 - ))); + hasher.update(Bytes::from(format!("{}", COMMON_PREFIX.len() + message.len() * 2))); hasher.update(Bytes::from(COMMON_PREFIX)); hasher.update(hex::encode(message)); let r = hasher.finalize(); @@ -1224,10 +1109,7 @@ pub struct BitcoinConfig { impl Default for BitcoinConfig { fn default() -> Self { - Self { - sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, - pubkey_err: false, - } + Self { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false } } } @@ -1280,11 +1162,7 @@ impl ChainConfig for BitcoinConfig { temp2.put_u8(0x40 + BTC_PREFIX.len() as u8); - temp2.put(Bytes::from(format!( - "{}{}", - BTC_PREFIX, - hex::encode(message) - ))); + temp2.put(Bytes::from(format!("{}{}", BTC_PREFIX, hex::encode(message)))); let msg = calculate_sha256(&temp2.to_vec()); let msg = calculate_sha256(&msg); @@ -1293,10 +1171,7 @@ impl ChainConfig for BitcoinConfig { } fn sign(&self, privkey: &Privkey, message: CkbH256) -> Bytes { - let sign = privkey - .sign_recoverable(&message) - .expect("sign secp256k1") - .serialize(); + let sign = privkey.sign_recoverable(&message).expect("sign secp256k1").serialize(); let recid = sign[64]; let mark = recid + self.sign_vtype; @@ -1450,6 +1325,13 @@ pub struct TestConfig { pub leading_witness_count: usize, pub chain_config: Option>, + pub cobuild_enabled: bool, + pub cobuild_message: Option, + pub custom_extension_witnesses: Option>, + pub custom_extension_witnesses_beginning: Option>, + pub random_tx: bool, + pub solana_secret_key: [u8; 32], + pub solana_phantom_sig: Option>, } #[derive(Copy, Clone, PartialEq)] @@ -1471,6 +1353,8 @@ pub enum TestScheme { OwnerLockWithoutWitness, RsaWrongSignature, + SolanaWrongSignature, + SolanaWrongPubkey, } #[derive(Copy, Clone, PartialEq)] @@ -1490,11 +1374,7 @@ impl TestConfig { let pubkey = private_key.pubkey().expect("pubkey"); let pubkey_hash = blake160(&pubkey.serialize()); - let blake160 = if flags == IDENTITY_FLAGS_PUBKEY_HASH { - pubkey_hash - } else { - Bytes::from(&[0; 20][..]) - }; + let blake160 = if flags == IDENTITY_FLAGS_PUBKEY_HASH { pubkey_hash } else { Bytes::from(&[0; 20][..]) }; let rc_root: Bytes = { let mut buf = BytesMut::new(); @@ -1548,6 +1428,13 @@ impl TestConfig { leading_witness_count: 0, chain_config: None, + cobuild_enabled: false, + cobuild_message: Some(Message::default()), + custom_extension_witnesses: None, + custom_extension_witnesses_beginning: None, + random_tx: true, + solana_secret_key: [0u8; 32], + solana_phantom_sig: None, } } @@ -1681,10 +1568,8 @@ pub fn gen_witness_lock( } if use_rc && use_rc_identity { - let rc_identity = omni_lock::IdentityBuilder::default() - .identity(identity.clone()) - .proofs(proofs.clone()) - .build(); + let rc_identity = + omni_lock::IdentityBuilder::default().identity(identity.clone()).proofs(proofs.clone()).build(); let opt = omni_lock::IdentityOpt::new_unchecked(rc_identity.as_bytes()); builder = builder.omni_identity(opt); } @@ -1809,28 +1694,38 @@ pub fn gen_zero_witness_lock( } else { None }; - let witness_lock = gen_witness_lock( - zero.freeze(), - use_rc, - use_rc_identity, - proofs, - identity, - preimage, - ); + let witness_lock = gen_witness_lock(zero.freeze(), use_rc, use_rc_identity, proofs, identity, preimage); let mut res = BytesMut::new(); res.resize(witness_lock.len(), 0); res.freeze() } +pub fn gen_dl_preimage(script: &Script, blake160: &Bytes) -> Bytes { + let mut result = BytesMut::new(); + result.put_slice(script.code_hash().as_slice()); + result.put_slice(script.hash_type().as_slice()); + result.put_slice(blake160.clone().as_ref()); + + result.freeze() +} + +// code hash: 32 bytes +// hash type: 1 byte +// place: 1 byte +// bounds: 8 bytes +// pubkey hash: 20 bytes pub fn gen_exec_preimage(script: &Script, blake160: &Bytes) -> Bytes { let mut result = BytesMut::new(); result.put_slice(script.code_hash().as_slice()); result.put_slice(script.hash_type().as_slice()); + result.put_slice(&[0u8; 1]); + result.put_slice(&[0u8; 8]); result.put_slice(blake160.clone().as_ref()); result.freeze() } + // first generate N RCE cells with each contained one RCRule // then collect all these RCE cell hash and create the final RCE cell. pub fn generate_rce_cell( @@ -1838,38 +1733,34 @@ pub fn generate_rce_cell( mut tx_builder: TransactionBuilder, rc_data: Vec, smt_in_input: bool, + config: &TestConfig, ) -> (Byte32, TransactionBuilder) { let mut rng = thread_rng(); let mut cell_vec_builder = RCCellVecBuilder::default(); for rc_rule in rc_data { let mut random_args: [u8; 32] = Default::default(); - rng.fill(&mut random_args[..]); + if config.random_tx { + rng.fill(&mut random_args[..]); + } // let's first build the RCE cell which contains the RCData(RCRule/RCCellVec). - let (b0, rce_script) = build_script( - dummy, - tx_builder, - true, - smt_in_input, - &rc_rule, - Bytes::copy_from_slice(random_args.as_ref()), - ); + let (b0, rce_script) = + build_script(dummy, tx_builder, true, smt_in_input, &rc_rule, Bytes::copy_from_slice(random_args.as_ref())); tx_builder = b0; // rce_script is in "old" blockchain types let hash = rce_script.code_hash(); - cell_vec_builder = - cell_vec_builder.push(Byte32::from_slice(hash.as_slice()).expect("Byte32::from_slice")); + cell_vec_builder = cell_vec_builder.push(Byte32::from_slice(hash.as_slice()).expect("Byte32::from_slice")); } let cell_vec = cell_vec_builder.build(); - let rce_cell_content = RCDataBuilder::default() - .set(RCDataUnion::RCCellVec(cell_vec)) - .build(); + let rce_cell_content = RCDataBuilder::default().set(RCDataUnion::RCCellVec(cell_vec)).build(); let mut random_args: [u8; 32] = Default::default(); - rng.fill(&mut random_args[..]); + if config.random_tx { + rng.fill(&mut random_args[..]); + } let bin = rce_cell_content.as_slice(); @@ -1887,10 +1778,7 @@ pub fn generate_rce_cell( (rce_script.code_hash(), tx_builder) } -pub fn generate_proofs( - scheme: TestScheme, - smt_key: &Vec<[u8; 32]>, -) -> (Vec>, Vec, Vec) { +pub fn generate_proofs(scheme: TestScheme, smt_key: &Vec<[u8; 32]>) -> (Vec>, Vec, Vec) { let mut proofs = Vec::>::default(); let mut rc_data = Vec::::default(); let mut proof_masks = Vec::::default(); @@ -2000,22 +1888,9 @@ pub fn assert_script_error(err: Error, err_code: i8) { ); } -pub fn gen_consensus() -> Consensus { - let hardfork_switch = HardForkSwitch::new_without_any_enabled() - .as_builder() - .rfc_0232(200) - .build() - .unwrap(); - ConsensusBuilder::default() - .hardfork_switch(hardfork_switch) - .build() -} - pub fn gen_tx_env() -> TxVerifyEnv { let epoch = EpochNumberWithFraction::new(300, 0, 1); - let header = HeaderView::new_advanced_builder() - .epoch(epoch.pack()) - .build(); + let header = HeaderView::new_advanced_builder().epoch(epoch.pack()).build(); TxVerifyEnv::new_commit(&header) } @@ -2040,3 +1915,74 @@ pub fn calculate_ripemd160(buf: &[u8]) -> [u8; 20] { pub fn bitcoin_hash160(buf: &[u8]) -> [u8; 20] { calculate_ripemd160(&calculate_sha256(buf)) } + +pub fn verify_tx( + resolved_tx: ResolvedTransaction, + data_loader: DummyDataLoader, +) -> TransactionScriptsVerifier { + let hard_fork = HardForks { + ckb2021: ckb_types::core::hardfork::CKB2021::new_mirana().as_builder().rfc_0032(5).build().unwrap(), + ckb2023: ckb_types::core::hardfork::CKB2023::new_mirana().as_builder().rfc_0049(10).build().unwrap(), + }; + let consensus = ConsensusBuilder::default().hardfork_switch(hard_fork).build(); + TransactionScriptsVerifier::new( + Arc::new(resolved_tx), + data_loader.clone(), + Arc::new(consensus), + Arc::new(TxVerifyEnv::new_commit( + &HeaderView::new_advanced_builder() + .epoch(ckb_types::core::EpochNumberWithFraction::new(5, 0, 1).pack()) + .build(), + )), + ) +} + +#[test] +fn test_gen_sign_msg() { + // generate_signing_message_hash(H256::from([1u8;32]), tx); +} + +pub fn cobuild_generate_signing_message_hash( + message: &Option, + data_loader: &mut DummyDataLoader, + tx: &TransactionView, +) -> [u8; 32] { + let mut count = 0; + // message + let mut hasher = match message { + Some(m) => { + let mut hasher = omni_lock_test::blake2b::new_sighash_all_blake2b(); + hasher.update(m.as_slice()); + count += m.as_slice().len(); + hasher + } + None => omni_lock_test::blake2b::new_sighash_all_only_blake2b(), + }; + // tx hash + hasher.update(tx.hash().as_slice()); + count += 32; + // inputs cell and data + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let (input_cell, input_cell_data) = data_loader.cells.get(&input_cell_out_point).unwrap(); + hasher.update(input_cell.as_slice()); + count += input_cell.as_slice().len(); + hasher.update(&(input_cell_data.len() as u32).to_le_bytes()); + count += 4; + hasher.update(input_cell_data); + count += input_cell_data.len(); + } + // extra witnesses + for witness in tx.witnesses().into_iter().skip(inputs_len) { + hasher.update(&(witness.len() as u32).to_le_bytes()); + count += 4; + hasher.update(&witness.raw_data()); + count += witness.raw_data().len(); + } + println!("cobuild_generate_signing_message_hash totally hashed {} bytes", count); + let mut result = [0u8; 32]; + hasher.finalize(&mut result); + result +} diff --git a/tests/omni_lock_rust/tests/test_anyone_can_pay.rs b/tests/omni_lock_rust/tests/test_anyone_can_pay.rs index 5f5b3e8..9e6d9b2 100644 --- a/tests/omni_lock_rust/tests/test_anyone_can_pay.rs +++ b/tests/omni_lock_rust/tests/test_anyone_can_pay.rs @@ -15,20 +15,17 @@ use lazy_static::lazy_static; use rand::{thread_rng, Rng, SeedableRng}; use misc::{ - assert_script_error, blake160, build_always_success_script, build_omni_lock_script, - build_resolved_tx, debug_printer, gen_tx, gen_tx_with_grouped_args, gen_witness_lock, sign_tx, - sign_tx_by_input_group, sign_tx_hash, DummyDataLoader, TestConfig, TestScheme, ALWAYS_SUCCESS, - ERROR_DUPLICATED_INPUTS, ERROR_DUPLICATED_OUTPUTS, ERROR_ENCODING, ERROR_NO_PAIR, - ERROR_OUTPUT_AMOUNT_NOT_ENOUGH, ERROR_PUBKEY_BLAKE160_HASH, ERROR_WITNESS_SIZE, - IDENTITY_FLAGS_PUBKEY_HASH, MAX_CYCLES, OMNI_LOCK, + assert_script_error, blake160, build_always_success_script, build_omni_lock_script, build_resolved_tx, + debug_printer, gen_tx, gen_tx_with_grouped_args, gen_witness_lock, sign_tx, sign_tx_by_input_group, sign_tx_hash, + verify_tx, DummyDataLoader, TestConfig, TestScheme, ALWAYS_SUCCESS, ERROR_DUPLICATED_INPUTS, + ERROR_DUPLICATED_OUTPUTS, ERROR_ENCODING, ERROR_NO_PAIR, ERROR_OUTPUT_AMOUNT_NOT_ENOUGH, + ERROR_PUBKEY_BLAKE160_HASH, ERROR_WITNESS_SIZE, IDENTITY_FLAGS_PUBKEY_HASH, MAX_CYCLES, OMNI_LOCK, }; mod misc; #[test] fn test_unlock_by_anyone() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -40,16 +37,11 @@ fn test_unlock_by_anyone() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .as_builder() - .lock(script) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.as_builder().lock(script).capacity(44u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass"); @@ -57,8 +49,6 @@ fn test_unlock_by_anyone() { #[test] fn test_put_output_data() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -70,17 +60,12 @@ fn test_put_output_data() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .as_builder() - .lock(script) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.as_builder().lock(script).capacity(44u64.pack()).build()]) .set_outputs_data(vec![Bytes::from(vec![42u8]).pack()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_ENCODING); @@ -88,8 +73,6 @@ fn test_put_output_data() { #[test] fn test_wrong_output_args() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -102,16 +85,11 @@ fn test_wrong_output_args() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .as_builder() - .lock(script) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.as_builder().lock(script).capacity(44u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_NO_PAIR); @@ -119,8 +97,6 @@ fn test_wrong_output_args() { #[test] fn test_split_cell() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -133,27 +109,14 @@ fn test_split_cell() { .as_advanced_builder() .set_witnesses(Vec::new()) .set_outputs(vec![ - output - .clone() - .as_builder() - .lock(script.clone()) - .capacity(44u64.pack()) - .build(), - output - .as_builder() - .lock(script) - .capacity(44u64.pack()) - .build(), - ]) - .set_outputs_data(vec![ - Bytes::from(Vec::new()).pack(), - Bytes::from(Vec::new()).pack(), + output.clone().as_builder().lock(script.clone()).capacity(44u64.pack()).build(), + output.as_builder().lock(script).capacity(44u64.pack()).build(), ]) + .set_outputs_data(vec![Bytes::from(Vec::new()).pack(), Bytes::from(Vec::new()).pack()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_DUPLICATED_OUTPUTS); @@ -161,8 +124,6 @@ fn test_split_cell() { #[test] fn test_merge_cell() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -174,17 +135,11 @@ fn test_merge_cell() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .clone() - .as_builder() - .lock(script.clone()) - .capacity(88u64.pack()) - .build()]) + .set_outputs(vec![output.clone().as_builder().lock(script.clone()).capacity(88u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_DUPLICATED_INPUTS); @@ -192,8 +147,6 @@ fn test_merge_cell() { #[test] fn test_insufficient_pay() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -205,17 +158,11 @@ fn test_insufficient_pay() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .clone() - .as_builder() - .lock(script.clone()) - .capacity(41u64.pack()) - .build()]) + .set_outputs(vec![output.clone().as_builder().lock(script.clone()).capacity(41u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_OUTPUT_AMOUNT_NOT_ENOUGH); @@ -223,8 +170,6 @@ fn test_insufficient_pay() { #[test] fn test_payment_not_meet_requirement() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((1, 0))); @@ -236,17 +181,11 @@ fn test_payment_not_meet_requirement() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .clone() - .as_builder() - .lock(script.clone()) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.clone().as_builder().lock(script.clone()).capacity(44u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_OUTPUT_AMOUNT_NOT_ENOUGH); @@ -254,8 +193,6 @@ fn test_payment_not_meet_requirement() { #[test] fn test_no_pair() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -266,17 +203,11 @@ fn test_no_pair() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .clone() - .as_builder() - .lock(another_script.clone()) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.clone().as_builder().lock(another_script.clone()).capacity(44u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_NO_PAIR); @@ -284,8 +215,6 @@ fn test_no_pair() { #[test] fn test_overflow() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((255, 0))); @@ -297,16 +226,11 @@ fn test_overflow() { let tx = tx .as_advanced_builder() .set_witnesses(Vec::new()) - .set_outputs(vec![output - .as_builder() - .lock(script) - .capacity(44u64.pack()) - .build()]) + .set_outputs(vec![output.as_builder().lock(script).capacity(44u64.pack()).build()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_OUTPUT_AMOUNT_NOT_ENOUGH); @@ -314,8 +238,6 @@ fn test_overflow() { #[test] fn test_only_pay_ckb() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); // do not accept UDT transfer @@ -326,14 +248,9 @@ fn test_only_pay_ckb() { let script = build_omni_lock_script(&mut config, args); let input = tx.inputs().get(0).unwrap(); let (prev_output, _) = data_loader.cells.remove(&input.previous_output()).unwrap(); - let prev_output = prev_output - .as_builder() - .type_(Some(build_always_success_script()).pack()) - .build(); + let prev_output = prev_output.as_builder().type_(Some(build_always_success_script()).pack()).build(); let prev_data = 44u128.to_le_bytes().to_vec().into(); - data_loader - .cells - .insert(input.previous_output(), (prev_output, prev_data)); + data_loader.cells.insert(input.previous_output(), (prev_output, prev_data)); let output = tx.outputs().get(0).unwrap(); let tx = tx .as_advanced_builder() @@ -348,8 +265,7 @@ fn test_only_pay_ckb() { .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass"); @@ -357,8 +273,6 @@ fn test_only_pay_ckb() { #[test] fn test_only_pay_udt() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); // do not accept CKB transfer @@ -370,14 +284,9 @@ fn test_only_pay_udt() { let input = tx.inputs().get(0).unwrap(); let (prev_output, _) = data_loader.cells.remove(&input.previous_output()).unwrap(); let input_capacity = prev_output.capacity(); - let prev_output = prev_output - .as_builder() - .type_(Some(build_always_success_script()).pack()) - .build(); + let prev_output = prev_output.as_builder().type_(Some(build_always_success_script()).pack()).build(); let prev_data = 43u128.to_le_bytes().to_vec().into(); - data_loader - .cells - .insert(input.previous_output(), (prev_output, prev_data)); + data_loader.cells.insert(input.previous_output(), (prev_output, prev_data)); let output = tx.outputs().get(0).unwrap(); let tx = tx .as_advanced_builder() @@ -392,8 +301,7 @@ fn test_only_pay_udt() { .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass"); @@ -401,8 +309,6 @@ fn test_only_pay_udt() { #[test] fn test_udt_unlock_by_anyone() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -412,14 +318,9 @@ fn test_udt_unlock_by_anyone() { let script = build_omni_lock_script(&mut config, args); let input = tx.inputs().get(0).unwrap(); let (prev_output, _) = data_loader.cells.remove(&input.previous_output()).unwrap(); - let prev_output = prev_output - .as_builder() - .type_(Some(build_always_success_script()).pack()) - .build(); + let prev_output = prev_output.as_builder().type_(Some(build_always_success_script()).pack()).build(); let prev_data = 43u128.to_le_bytes().to_vec().into(); - data_loader - .cells - .insert(input.previous_output(), (prev_output, prev_data)); + data_loader.cells.insert(input.previous_output(), (prev_output, prev_data)); let output = tx.outputs().get(0).unwrap(); let tx = tx .as_advanced_builder() @@ -434,8 +335,7 @@ fn test_udt_unlock_by_anyone() { .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass"); @@ -443,8 +343,6 @@ fn test_udt_unlock_by_anyone() { #[test] fn test_udt_overflow() { - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); // do not accept CKB transfer @@ -455,14 +353,9 @@ fn test_udt_overflow() { let script = build_omni_lock_script(&mut config, args); let input = tx.inputs().get(0).unwrap(); let (prev_output, _) = data_loader.cells.remove(&input.previous_output()).unwrap(); - let prev_output = prev_output - .as_builder() - .type_(Some(build_always_success_script()).pack()) - .build(); + let prev_output = prev_output.as_builder().type_(Some(build_always_success_script()).pack()).build(); let prev_data = 43u128.to_le_bytes().to_vec().into(); - data_loader - .cells - .insert(input.previous_output(), (prev_output, prev_data)); + data_loader.cells.insert(input.previous_output(), (prev_output, prev_data)); let output = tx.outputs().get(0).unwrap(); let tx = tx .as_advanced_builder() @@ -477,8 +370,7 @@ fn test_udt_overflow() { .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_OUTPUT_AMOUNT_NOT_ENOUGH); @@ -487,8 +379,7 @@ fn test_udt_overflow() { #[test] fn test_extended_udt() { // we assume the first 16 bytes data represent token amount - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); + let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, false); config.set_acp_config(Some((0, 0))); @@ -498,16 +389,11 @@ fn test_extended_udt() { let script = build_omni_lock_script(&mut config, args); let input = tx.inputs().get(0).unwrap(); let (prev_output, _) = data_loader.cells.remove(&input.previous_output()).unwrap(); - let prev_output = prev_output - .as_builder() - .type_(Some(build_always_success_script()).pack()) - .build(); + let prev_output = prev_output.as_builder().type_(Some(build_always_success_script()).pack()).build(); let mut prev_data = 43u128.to_le_bytes().to_vec(); // push junk data prev_data.push(42); - data_loader - .cells - .insert(input.previous_output(), (prev_output, prev_data.into())); + data_loader.cells.insert(input.previous_output(), (prev_output, prev_data.into())); let output = tx.outputs().get(0).unwrap(); let mut output_udt = 44u128.to_le_bytes().to_vec(); // push junk data @@ -525,8 +411,7 @@ fn test_extended_udt() { .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass"); diff --git a/tests/omni_lock_rust/tests/test_multisig.rs b/tests/omni_lock_rust/tests/test_multisig.rs index 0c41884..1041992 100644 --- a/tests/omni_lock_rust/tests/test_multisig.rs +++ b/tests/omni_lock_rust/tests/test_multisig.rs @@ -10,16 +10,14 @@ use ckb_script::{ScriptError, ScriptGroupType, TransactionScriptsVerifier, TxVer use ckb_types::{ bytes::Bytes, bytes::BytesMut, - core::{ - cell::ResolvedTransaction, hardfork::HardForkSwitch, EpochNumberWithFraction, HeaderView, - }, + core::{cell::ResolvedTransaction, EpochNumberWithFraction, HeaderView}, packed::WitnessArgs, prelude::*, H256, }; use lazy_static::lazy_static; use misc::*; -use omni_lock_test::debug_utils::debug; +// use omni_lock_test::debug_utils::debug; use std::fs; // Script args validation errors @@ -43,10 +41,7 @@ fn test_multisig_0_2_3_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -67,11 +62,7 @@ fn test_multisig_invalid_flags() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_MULTSIG_SCRIPT_HASH) @@ -91,11 +82,7 @@ fn test_multisig_invalid_flags2() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_MULTSIG_SCRIPT_HASH) @@ -114,11 +101,7 @@ fn test_multisig_1_2_3_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -137,11 +120,7 @@ fn test_multisig_3_7_15_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -160,11 +139,7 @@ fn test_multisig_0_1_1_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -183,11 +158,7 @@ fn test_multisig_0_2_2_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -196,8 +167,8 @@ fn test_multisig_0_2_2_unlock() { #[test] #[ignore] fn test_multisig_0_2_3_unlock_smt_in_input_debug() { - let binary = fs::read("../../../build/omni_lock.debug").expect("read_to_string"); - let omni_lock_debug = Bytes::from(binary); + // let binary = fs::read("../../../build/omni_lock.debug").expect("read_to_string"); + // let omni_lock_debug = Bytes::from(binary); let mut data_loader = DummyDataLoader::new(); @@ -211,21 +182,17 @@ fn test_multisig_0_2_3_unlock_smt_in_input_debug() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); - debug( - "127.0.0.1:9999", - ScriptGroupType::Lock, - config.running_script.calc_script_hash(), - &omni_lock_debug, - &[], - &verifier, - ); + // debug( + // "127.0.0.1:9999", + // ScriptGroupType::Lock, + // config.running_script.calc_script_hash(), + // &omni_lock_debug, + // &[], + // &verifier, + // ); } #[test] @@ -242,10 +209,374 @@ fn test_multisig_0_2_3_unlock_smt_in_input() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_multisig_0_2_3_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, true); + config.cobuild_enabled = true; + config.set_multisig(0, 2, 3); + + config.scheme = TestScheme::OnWhiteList; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_multisig_invalid_flags() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, true); + config.set_multisig(0, 2, 3); + config.multisig.set(0, 2, 4); + config.cobuild_enabled = true; + + config.scheme = TestScheme::OnWhiteList; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_MULTSIG_SCRIPT_HASH) +} + +#[test] +fn test_cobuild_multisig_invalid_flags2() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, true); + config.set_multisig(0, 2, 3); + config.multisig.set(0, 3, 3); + config.cobuild_enabled = true; + + config.scheme = TestScheme::OnWhiteList; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_MULTSIG_SCRIPT_HASH) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_zero() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x0000_0000_8888_8888u64; + config.set_since(since, 0); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_VALUE) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_minus_1() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x0000_0000_8888_8888u64; + config.set_since(since, since - 1); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_VALUE) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_eq() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x0000_0000_8888_8888u64; + config.set_since(since, since); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_relative_eq() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x8000_0000_8888_8888u64; + config.set_since(since, since); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_relative_not_comparable() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x8000_0000_8888_8888u64; + let since2 = 0x0000_0000_8888_8888u64; + config.set_since(since, since2); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_FLAGS) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_flags() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x0000_0000_8888_8888u64; + config.set_since(since, since | 0x2000_0000_0000_0000); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_FLAGS) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_add_1() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = 0x0000_0000_8888_8888u64; + config.set_since(since, since + 1); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +lazy_static! { + static ref TESTDATA_SINCE_EPOCH: EpochNumberWithFraction = EpochNumberWithFraction::new(200, 5, 100); + static ref TESTDATA_SINCE_EPOCH_VAL: u64 = 0x2000_0000_0000_0000u64; +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + config.set_since(since, 0); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_FLAGS) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add1() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + let epoch = EpochNumberWithFraction::new(200, 2, 200); + config.set_since(since, TESTDATA_SINCE_EPOCH_VAL.clone() + epoch.full_value()); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_VALUE) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add2() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + let epoch = EpochNumberWithFraction::new(200, 1, 600); + config.set_since(since, TESTDATA_SINCE_EPOCH_VAL.clone() + epoch.full_value()); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_VALUE) +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add3() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + let epoch = EpochNumberWithFraction::new(200, 6, 50); + config.set_since(since, TESTDATA_SINCE_EPOCH_VAL.clone() + epoch.full_value()); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add4() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + let epoch = EpochNumberWithFraction::new(200, 1, 2); + config.set_since(since, TESTDATA_SINCE_EPOCH_VAL.clone() + epoch.full_value()); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add5() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + let epoch = EpochNumberWithFraction::new(200, 6, 100); + config.set_since(since, TESTDATA_SINCE_EPOCH_VAL.clone() + epoch.full_value()); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_add6() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + config.set_since(since, since + 1); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_multisig_0_2_3_unlock_with_since_epoch_eq() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_MULTISIG, false); + config.set_multisig(0, 2, 3); + + let since = TESTDATA_SINCE_EPOCH_VAL.clone() + TESTDATA_SINCE_EPOCH.full_value(); + + config.set_since(since, since); + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); diff --git a/tests/omni_lock_rust/tests/test_omni_lock.rs b/tests/omni_lock_rust/tests/test_omni_lock.rs index 69649d5..31136e1 100644 --- a/tests/omni_lock_rust/tests/test_omni_lock.rs +++ b/tests/omni_lock_rust/tests/test_omni_lock.rs @@ -3,22 +3,30 @@ mod misc; +use std::fs::File; +use std::hash::Hash; +use std::io::Read; + +use blake2b_rs::{Blake2b, Blake2bBuilder}; use ckb_chain_spec::consensus::ConsensusBuilder; use ckb_crypto::secp::Generator; use ckb_error::assert_error_eq; use ckb_script::{ScriptError, TransactionScriptsVerifier, TxVerifyEnv}; +use ckb_types::core::hardfork::HardForks; +use ckb_types::packed::ScriptOpt; use ckb_types::{ bytes::Bytes, bytes::BytesMut, - core::{ - cell::ResolvedTransaction, hardfork::HardForkSwitch, EpochNumberWithFraction, HeaderView, - }, - packed::WitnessArgs, + core::{cell::ResolvedTransaction, EpochNumberWithFraction, HeaderView}, + packed::{CellInput, WitnessArgs}, prelude::*, H256, }; +use ed25519_dalek::SigningKey; use lazy_static::lazy_static; use misc::*; +use omni_lock_test::schemas::{basic::*, blockchain::WitnessArgsBuilder, top_level::*}; +use std::sync::Arc; // // owner lock section @@ -35,33 +43,9 @@ fn test_simple_owner_lock() { // For ckb 0.40.0 // let mut verifier = - // TransactionScriptsVerifier::new(&resolved_tx, &data_loader); - - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - - verifier.set_debug_printer(debug_printer); - let verify_result = verifier.verify(MAX_CYCLES); - verify_result.expect("pass verification"); -} - -#[test] -fn test_owner_lock_without_witness() { - let mut data_loader = DummyDataLoader::new(); - - let mut config = TestConfig::new(IDENTITY_FLAGS_OWNER_LOCK, false); - config.scheme2 = TestScheme2::NoWitness; - - let tx = gen_tx(&mut data_loader, &mut config); - let tx = sign_tx(&mut data_loader, tx, &mut config); - let resolved_tx = build_resolved_tx(&data_loader, &tx); + // TransactionScriptsVerifier::new(&resolved_tx, data_loader); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -79,10 +63,7 @@ fn test_simple_owner_lock_mismatched() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -100,38 +81,13 @@ fn test_owner_lock_on_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } -#[test] -fn test_owner_lock_on_wl_without_witness() { - let mut data_loader = DummyDataLoader::new(); - - let mut config = TestConfig::new(IDENTITY_FLAGS_OWNER_LOCK, true); - config.scheme = TestScheme::OnWhiteList; - config.scheme2 = TestScheme2::NoWitness; - - let tx = gen_tx(&mut data_loader, &mut config); - let tx = sign_tx(&mut data_loader, tx, &mut config); - let resolved_tx = build_resolved_tx(&data_loader, &tx); - - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - - verifier.set_debug_printer(debug_printer); - let verify_result = verifier.verify(MAX_CYCLES); - assert!(verify_result.is_err()); -} - #[test] fn test_owner_lock_not_on_wl() { let mut data_loader = DummyDataLoader::new(); @@ -143,10 +99,7 @@ fn test_owner_lock_not_on_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -166,10 +119,7 @@ fn test_owner_lock_no_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -187,10 +137,7 @@ fn test_owner_lock_on_bl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -208,10 +155,7 @@ fn test_owner_lock_emergency_halt_mode() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -233,10 +177,7 @@ fn test_pubkey_hash_on_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); @@ -255,38 +196,13 @@ fn test_pubkey_hash_without_omni_identity() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } -#[test] -fn test_pubkey_hash_on_wl_without_witness() { - let mut data_loader = DummyDataLoader::new(); - - let mut config = TestConfig::new(IDENTITY_FLAGS_PUBKEY_HASH, true); - config.scheme = TestScheme::OnWhiteList; - config.scheme2 = TestScheme2::NoWitness; - - let tx = gen_tx(&mut data_loader, &mut config); - let tx = sign_tx(&mut data_loader, tx, &mut config); - let resolved_tx = build_resolved_tx(&data_loader, &tx); - - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - - verifier.set_debug_printer(debug_printer); - let verify_result = verifier.verify(MAX_CYCLES); - assert!(verify_result.is_err()); -} - #[test] fn test_pubkey_hash_not_on_wl() { let mut data_loader = DummyDataLoader::new(); @@ -298,11 +214,7 @@ fn test_pubkey_hash_not_on_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_NOT_ON_WHITE_LIST) @@ -321,11 +233,7 @@ fn test_pubkey_hash_no_wl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_NO_WHITE_LIST) @@ -342,11 +250,7 @@ fn test_pubkey_hash_on_bl() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_ON_BLACK_LIST) @@ -363,102 +267,61 @@ fn test_pubkey_hash_emergency_halt_mode() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_RCE_EMERGENCY_HALT) } #[test] -fn test_rsa_via_dl_unlock() { +fn test_via_exec_unlock() { let mut data_loader = DummyDataLoader::new(); - let mut config = TestConfig::new(IDENTITY_FLAGS_DL, false); - config.set_rsa(); + let mut config = TestConfig::new(IDENTITY_FLAGS_EXEC, false); let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } #[test] -fn test_rsa_via_dl_wrong_sig() { - let mut data_loader = DummyDataLoader::new(); - - let mut config = TestConfig::new(IDENTITY_FLAGS_DL, false); - config.set_rsa(); - config.scheme = TestScheme::RsaWrongSignature; - - let tx = gen_tx(&mut data_loader, &mut config); - let tx = sign_tx(&mut data_loader, tx, &mut config); - let resolved_tx = build_resolved_tx(&data_loader, &tx); - - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - verifier.set_debug_printer(debug_printer); - let verify_result = verifier.verify(MAX_CYCLES); - assert_script_error(verify_result.unwrap_err(), ERROR_RSA_VERIFY_FAILED); -} - -#[test] -fn test_rsa_via_dl_unlock_with_time_lock() { +fn test_rsa_via_dl_unlock() { let mut data_loader = DummyDataLoader::new(); - let args_since = 0x2000_0000_0000_0000u64 + 200; - let input_since = 0x2000_0000_0000_0000u64 + 200; let mut config = TestConfig::new(IDENTITY_FLAGS_DL, false); config.set_rsa(); - config.set_since(args_since, input_since); let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } #[test] -fn test_rsa_via_dl_unlock_with_time_lock_failed() { +fn test_rsa_via_dl_wrong_sig() { let mut data_loader = DummyDataLoader::new(); - let args_since = 0x2000_0000_0000_0000u64 + 200; - let input_since = 0x2000_0000_0000_0000u64 + 100; let mut config = TestConfig::new(IDENTITY_FLAGS_DL, false); config.set_rsa(); - config.set_since(args_since, input_since); + config.scheme = TestScheme::RsaWrongSignature; let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); - - assert_script_error(verify_result.unwrap_err(), ERROR_INCORRECT_SINCE_VALUE); + assert_script_error(verify_result.unwrap_err(), ERROR_RSA_VERIFY_FAILED); } // currently, the signature can only be signed via hardware. @@ -474,10 +337,7 @@ fn test_iso9796_2_batch_via_dl_unlock_failed() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = gen_consensus(); - let tx_env = gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert!(verify_result.is_err()); @@ -494,11 +354,7 @@ fn test_eth_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -508,22 +364,35 @@ fn test_btc_success(vtype: u8) { let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); - config.set_chain_config(Box::new(BitcoinConfig { - sign_vtype: vtype, - pubkey_err: false, - })); + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: vtype, pubkey_err: false })); let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +fn test_cobuild_btc_success(vtype: u8) { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: vtype, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); + let cycles = verify_result.clone().unwrap(); + // about ~1429386 + assert!(cycles < 1500000); verify_result.expect("pass verification"); } @@ -531,20 +400,13 @@ fn test_btc_err_pubkey(vtype: u8) { let mut data_loader = DummyDataLoader::new(); let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); - config.set_chain_config(Box::new(BitcoinConfig { - sign_vtype: vtype, - pubkey_err: true, - })); + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: vtype, pubkey_err: true })); let tx = gen_tx(&mut data_loader, &mut config); let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert!(verify_result.is_err()); @@ -564,6 +426,11 @@ fn test_btc_unlock() { test_btc(BITCOIN_V_TYPE_SEGWITBECH32); } +#[test] +fn test_cobuild_btc_native_segwit() { + test_cobuild_btc_success(BITCOIN_V_TYPE_P2PKHCOMPRESSED); +} + #[test] fn test_dogecoin_unlock() { let mut data_loader = DummyDataLoader::new(); @@ -575,11 +442,7 @@ fn test_dogecoin_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -598,11 +461,7 @@ fn test_dogecoin_err_pubkey() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert!(verify_result.is_err()) @@ -620,11 +479,7 @@ fn test_eos_success(vtype: u8) { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -643,11 +498,7 @@ fn test_eos_err_pubkey(vtype: u8) { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert!(verify_result.is_err()); @@ -676,11 +527,7 @@ fn test_tron_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -699,11 +546,7 @@ fn test_tron_err_pubkey() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); assert!(verify_result.is_err()); @@ -721,12 +564,878 @@ fn test_eth_displaying_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_solana_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_SOLANA, false); + config.solana_secret_key = [0x01u8; 32]; + config.sig_len = 96; + + let signing_key = SigningKey::from_bytes(&config.solana_secret_key); + let verifying_key = signing_key.verifying_key(); + let blake160 = blake160(&verifying_key.to_bytes()); + let auth = Identity { flags: IDENTITY_FLAGS_SOLANA, blake160 }; + config.id = auth; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_solana_wrong_pubkey() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_SOLANA, false); + config.solana_secret_key = [0x01u8; 32]; + config.sig_len = 96; + config.scheme = TestScheme::SolanaWrongPubkey; + + let signing_key = SigningKey::from_bytes(&config.solana_secret_key); + let verifying_key = signing_key.verifying_key(); + let blake160 = blake160(&verifying_key.to_bytes()); + let auth = Identity { flags: IDENTITY_FLAGS_SOLANA, blake160 }; + config.id = auth; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_MISMATCHED); +} + +#[test] +fn test_solana_wrong_signature() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_SOLANA, false); + config.solana_secret_key = [0x01u8; 32]; + config.sig_len = 96; + config.scheme = TestScheme::SolanaWrongSignature; + + let signing_key = SigningKey::from_bytes(&config.solana_secret_key); + let verifying_key = signing_key.verifying_key(); + let blake160 = blake160(&verifying_key.to_bytes()); + let auth = Identity { flags: IDENTITY_FLAGS_SOLANA, blake160 }; + config.id = auth; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_MISMATCHED); +} + +/// Steps to update this test case: +/// +/// 1. Install Phantom wallet from: [Phantom Wallet](https://phantom.app/) +/// 2. Create an account on the wallet and obtain the Solana address. Update it +/// to the variable `address`. +/// 3. Run `cargo test test_solana_phantom_wallet -- --nocapture`. Find the +/// message to sign, for example: +/// ``` +/// Message to be signed by ed25519: CKB transaction: +/// 0x761f6986168340c33dfe016c7274fc30b3339d6d29dacc594f93addc700704fe +/// ``` +/// 4. Sign the message using [Phantom's message signing functionality](https://docs.phantom.app/solana/signing-a-message), e.g.: +/// ``` +/// provider.signMessage(new TextEncoder().encode("CKB transaction: +/// 0x761f6986168340c33dfe016c7274fc30b3339d6d29dacc594f93addc700704fe"), +/// "utf8") +/// ``` +/// 5. Update the variable `sig` with the obtained signature. +/// +#[test] +fn test_solana_phantom_wallet() { + let mut data_loader = DummyDataLoader::new(); + let address = "FK577f9qN4jiUJkQoiXvjuCcwmwLmB3sWwzBzX3ij8wG"; + let mut sig = vec![ + 139, 30, 199, 50, 16, 72, 145, 222, 75, 218, 182, 90, 47, 14, 110, 181, 226, 204, 15, 118, 122, 239, 221, 181, + 120, 164, 215, 252, 0, 72, 232, 235, 80, 74, 74, 107, 48, 10, 90, 145, 212, 44, 198, 233, 76, 253, 51, 91, 235, + 252, 117, 77, 242, 40, 68, 155, 143, 28, 252, 98, 94, 179, 6, 0, + ]; + + let verifying_key = bs58::decode(address).into_vec().unwrap(); + sig.extend(verifying_key.clone()); + + let mut config = TestConfig::new(IDENTITY_FLAGS_SOLANA, false); + config.random_tx = false; + config.sig_len = 96; + + let blake160 = blake160(&verifying_key); + let auth = Identity { flags: IDENTITY_FLAGS_SOLANA, blake160 }; + config.id = auth; + assert_eq!(sig.len(), 96); + config.solana_phantom_sig = Some(sig); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +// this test can fail during development +// TODO: enable it when ready +#[test] +fn test_binary_unchanged() { + let mut buf = [0u8; 8 * 1024]; + // build hash + let mut blake2b = Blake2bBuilder::new(32).personal(b"ckb-default-hash").build(); + + let mut fd = File::open("../../build/omni_lock").expect("open file"); + loop { + let read_bytes = fd.read(&mut buf).expect("read file"); + if read_bytes > 0 { + blake2b.update(&buf[..read_bytes]); + } else { + break; + } + } + + let mut hash = [0u8; 32]; + blake2b.finalize(&mut hash); + + let actual_hash = faster_hex::hex_string(&hash); + assert_eq!("3f303aa87238dbc34a81a1c42109e07aad9c8e4ab3e8741d87fffca43851b2d7", &actual_hash); +} + +#[test] +fn test_cobuild_no_has_message() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses = Some(vec![Bytes::from([00, 00].to_vec())]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_append_witnessed_less_than_4() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses = + Some(vec![Bytes::from([00, 01, 00].to_vec()), Bytes::from([00, 00, 00, 00].to_vec()), Bytes::new()]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_non_empty_witness() { + let mut data_loader = DummyDataLoader::new(); + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let lock_args = config.gen_args(); + let tx = gen_tx_with_grouped_args(&mut data_loader, vec![(lock_args, 2)], &mut config); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), 112); +} + +#[test] +fn test_cobuild_input_cell_data_size_0() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_input_cell_data_size_1() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let (input_cell_output, _) = data_loader.cells.get(&input_cell_out_point).unwrap(); + data_loader.cells.insert(input_cell_out_point, (input_cell_output.clone(), Bytes::from(vec![0x42; 1]))); + } + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_input_cell_data_size_2048() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let (input_cell_output, _) = data_loader.cells.get(&input_cell_out_point).unwrap(); + data_loader.cells.insert(input_cell_out_point, (input_cell_output.clone(), Bytes::from(vec![0x42; 2048]))); + } + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_input_cell_data_size_2049() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let (input_cell_output, _) = data_loader.cells.get(&input_cell_out_point).unwrap(); + data_loader.cells.insert(input_cell_out_point, (input_cell_output.clone(), Bytes::from(vec![0x42; 2049]))); + } + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } + +#[test] +fn test_cobuild_input_cell_data_size_500k() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let (input_cell_output, _) = data_loader.cells.get(&input_cell_out_point).unwrap(); + data_loader + .cells + .insert(input_cell_out_point, (input_cell_output.clone(), Bytes::from(vec![0x42; 500 * 1024]))); + } + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_wrong_union_id() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + + let witness = tx.witnesses().get(0).unwrap(); + let mut witness_builder = witness.as_builder(); + witness_builder.replace(0, 0x03.into()); + let witness = witness_builder.build(); + let tx = tx.as_advanced_builder().set_witnesses(vec![witness]).build(); + + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), 8); // MOL2_ERR_OVERFLOW +} + +#[test] +fn test_cobuild_sighash_all_only() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.cobuild_message = None; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + let cycles = (&verify_result).as_ref().unwrap(); + println!("cycles = {}", *cycles); + // about ~1419872 + assert!(*cycles < 1430000); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_append_witnessargs() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses = + Some(vec![WitnessArgsBuilder::default().lock(Some(Bytes::from([0u8; 65].to_vec())).pack()).build().as_bytes()]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_append_other_witnesslayout() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses = Some(vec![WitnessLayoutBuilder::default() + .set(WitnessLayoutUnion::SighashAllOnly( + SighashAllOnlyBuilder::default().seal(Bytes::from([0u8; 32].to_vec()).pack()).build(), + )) + .build() + .as_bytes()]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_sighashall_dup() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + const WSITNESS_LAYOUT_SIGHASH_ALL: u32 = 4278190081; + let mut witness = Vec::new(); + witness.resize(6, 0); + witness[..4].copy_from_slice(&WSITNESS_LAYOUT_SIGHASH_ALL.to_le_bytes()); + + config.custom_extension_witnesses = Some(vec![Bytes::from(witness)]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), 7); // MOL2_ERR_DATA +} + +#[test] +fn test_cobuild_no_cobuild_append_sighash_all() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses = Some(vec![Bytes::from( + WitnessLayoutBuilder::default() + .set(WitnessLayoutUnion::SighashAll( + SighashAllBuilder::default() + .message(MessageBuilder::default().build()) + .seal(Bytes::from([0u8; 32].to_vec()).pack()) + .build(), + )) + .build() + .as_bytes(), + )]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), 114) +} + +#[test] +fn test_cobuild_insert_witness_less_4_before_sighashall() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + config.custom_extension_witnesses_beginning = Some(vec![Bytes::from([00, 01, 02].to_vec())]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.unwrap_err(); +} + +#[test] +fn test_cobuild_big_message() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + + let always_success_script = build_always_success_script(); + let always_success_script_hash = always_success_script.calc_script_hash(); + let always_success_script_opt = ScriptOpt::new_builder().set(Some(always_success_script)).build(); + + let mut action_vec = Vec::::new(); + for _ in 0..12 { + let action_builder = Action::new_builder(); + let action_builder = + action_builder.script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()); + let action_builder = action_builder.script_hash(always_success_script_hash.clone()); + let action_builder = action_builder.data(vec![0x42; 1024 * 40].pack()); + let action = action_builder.build(); + action_vec.push(action); + } + let action_vec = ActionVec::new_builder().extend(action_vec).build(); + let message = Message::new_builder().actions(action_vec).build(); + config.cobuild_message = Some(message); // Message is 500K bytes in molecule type. + + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + + let output0 = tx.output(0).unwrap().as_builder().type_(always_success_script_opt).build(); + let tx = tx.as_advanced_builder().set_outputs(vec![output0]).build(); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + // Print tx in json format. + // + // [dependencies] + // ckb-jsonrpc-types = "0.113.0" + // serde = "*" + // serde_json = "*" + // + // let tx_json = ckb_jsonrpc_types::TransactionView::from(resolved_tx.transaction.clone()); + // println!("{}", serde_json::to_string(&tx_json).unwrap()); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + let cycles = verify_result.as_ref().unwrap(); + println!("cycles = {}", *cycles); + assert!(*cycles < 16_000_000); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_simple_owner_lock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_OWNER_LOCK, false); + config.cobuild_enabled = true; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_simple_owner_lock_mismatched() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_OWNER_LOCK, false); + config.cobuild_enabled = true; + config.scheme = TestScheme::OwnerLockMismatched; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_LOCK_SCRIPT_HASH_NOT_FOUND) +} + +#[test] +fn test_cobuild_owner_lock_on_wl() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_OWNER_LOCK, true); + config.cobuild_enabled = true; + config.scheme = TestScheme::OnWhiteList; + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_append_witnessargs_acp() { + let mut data_loader: DummyDataLoader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + config.set_acp_config(Some((0, 0))); + + config.custom_extension_witnesses = + Some(vec![WitnessArgsBuilder::default().lock(Some(Bytes::from([0u8; 65].to_vec())).pack()).build().as_bytes()]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_append_other_witnesslayout_acp() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + config.set_acp_config(Some((0, 0))); + + config.custom_extension_witnesses = Some(vec![WitnessLayoutBuilder::default() + .set(WitnessLayoutUnion::SighashAllOnly( + SighashAllOnlyBuilder::default().seal(Bytes::from([0u8; 32].to_vec()).pack()).build(), + )) + .build() + .as_bytes()]); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_eth_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(EthereumConfig::default())); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_eth_displaying_unlock() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM_DISPLAYING, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(EthereumDisplayConfig::default())); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_check_action_script_hash_is_in_inputs() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + + let always_success_script = build_always_success_script(); + let always_success_script_hash = always_success_script.calc_script_hash(); + let always_success_script_opt = ScriptOpt::new_builder().set(Some(always_success_script)).build(); + + let mut action_vec = Vec::::new(); + let action_builder = Action::new_builder(); + let action_builder = action_builder.script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()); + let action_builder = action_builder.script_hash(always_success_script_hash.clone()); + let action_builder = action_builder.data(vec![0x42; 128].pack()); + let action = action_builder.build(); + action_vec.push(action); + let action_vec = ActionVec::new_builder().extend(action_vec).build(); + let message = Message::new_builder().actions(action_vec).build(); + config.cobuild_message = Some(message); + + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let (cell, cell_data) = data_loader.cells.get(&tx.inputs().get(0).unwrap().previous_output()).unwrap(); + let cell = cell.clone().as_builder().type_(always_success_script_opt).build(); + data_loader.cells.insert(tx.inputs().get(0).unwrap().previous_output(), (cell.clone(), cell_data.clone())); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_cobuild_check_action_script_hash_is_in_2_outputs() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config.cobuild_enabled = true; + + let always_success_script_0 = build_always_success_script(); + let always_success_script_1 = build_always_success_script(); + let always_success_script_0 = always_success_script_0.as_builder().args(vec![0x00].pack()).build(); + let always_success_script_1 = always_success_script_1.as_builder().args(vec![0x01].pack()).build(); + let always_success_script_hash_0 = always_success_script_0.calc_script_hash(); + let always_success_script_hash_1 = always_success_script_1.calc_script_hash(); + let always_success_script_opt_0 = ScriptOpt::new_builder().set(Some(always_success_script_0)).build(); + let always_success_script_opt_1 = ScriptOpt::new_builder().set(Some(always_success_script_1)).build(); + + let mut action_vec = Vec::::new(); + let action_builder_0 = Action::new_builder(); + let action_builder_0 = + action_builder_0.script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()); + let action_builder_0 = action_builder_0.script_hash(always_success_script_hash_0.clone()); + let action_builder_0 = action_builder_0.data(vec![0x42; 128].pack()); + let action_0 = action_builder_0.build(); + action_vec.push(action_0.clone()); + let action_builder_1 = Action::new_builder(); + let action_builder_1 = + action_builder_1.script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()); + let action_builder_1 = action_builder_1.script_hash(always_success_script_hash_1.clone()); + let action_builder_1 = action_builder_1.data(vec![0x42; 128].pack()); + let action_1 = action_builder_1.build(); + action_vec.push(action_1); + + let action_vec = ActionVec::new_builder().extend(action_vec).build(); + let message = Message::new_builder().actions(action_vec).build(); + config.cobuild_message = Some(message); // Message is 651300 bytes in molecule type. + + config.set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + + let output0 = tx.output(0).unwrap().as_builder().type_(always_success_script_opt_0).build(); + let output1 = tx.output(0).unwrap().as_builder().type_(always_success_script_opt_1).build(); + let tx = tx + .as_advanced_builder() + .set_outputs(vec![output0, output1]) + .outputs_data(vec![vec![0x00].pack(), vec![0x00].pack()]) + .build(); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_none_witness() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config + .set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHUNCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let tx = tx.as_advanced_builder().set_witnesses(Vec::new()).build(); + + let resolved_tx: ResolvedTransaction = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_IDENTITY_WRONG_ARGS); +} + +#[test] +fn test_big_output_data() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config + .set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHUNCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = tx.as_advanced_builder().set_outputs_data(vec![[0u8; 1024 * 700].pack()]).build(); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx: ResolvedTransaction = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_big_witness() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config + .set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHUNCOMPRESSED, pubkey_err: false })); + + let tx = gen_tx(&mut data_loader, &mut config); + let tx = tx.as_advanced_builder().witness([0u8; 1024 * 700].pack()).build(); + + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx: ResolvedTransaction = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + verify_result.expect("pass verification"); +} + +#[test] +fn test_big_script() { + let mut data_loader = DummyDataLoader::new(); + + let mut config = TestConfig::new(IDENTITY_FLAGS_BITCOIN, false); + config + .set_chain_config(Box::new(BitcoinConfig { sign_vtype: BITCOIN_V_TYPE_P2PKHUNCOMPRESSED, pubkey_err: false })); + + let lock_args = config.gen_args(); + + let lock_args = Bytes::from(vec![lock_args.to_vec(), vec![0u8; 1024 * 700]].concat()); + + let tx = gen_tx_with_grouped_args(&mut data_loader, vec![(lock_args, 1)], &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx: ResolvedTransaction = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + assert_script_error(verify_result.unwrap_err(), ERROR_ARGS_FORMAT); +} diff --git a/tests/omni_lock_rust/tests/test_otx.rs b/tests/omni_lock_rust/tests/test_otx.rs new file mode 100644 index 0000000..4257f89 --- /dev/null +++ b/tests/omni_lock_rust/tests/test_otx.rs @@ -0,0 +1,1383 @@ +use ckb_types::prelude::{Builder, Entity, Pack, Unpack}; +use molecule::prelude::Reader; +use omni_lock_test::schemas; +use rand::seq::SliceRandom; +use rand::RngCore; +use std::collections::{HashMap, HashSet}; +use std::str::FromStr; +use std::sync::Arc; + +#[derive(Clone, Default)] +pub struct Resource { + pub cell: HashMap, +} + +impl ckb_traits::CellDataProvider for Resource { + fn get_cell_data(&self, out_point: &ckb_types::packed::OutPoint) -> Option { + self.cell.get(out_point).and_then(|cell_meta| cell_meta.mem_cell_data.clone()) + } + + fn get_cell_data_hash(&self, out_point: &ckb_types::packed::OutPoint) -> Option { + self.cell.get(out_point).and_then(|cell_meta| cell_meta.mem_cell_data_hash.clone()) + } +} + +impl ckb_traits::HeaderProvider for Resource { + fn get_header(&self, _: &ckb_types::packed::Byte32) -> Option { + unimplemented!() + } +} + +impl ckb_traits::ExtensionProvider for Resource { + fn get_block_extension(&self, _: &ckb_types::packed::Byte32) -> Option { + unimplemented!() + } +} + +impl ckb_types::core::cell::CellProvider for Resource { + fn cell(&self, out_point: &ckb_types::packed::OutPoint, eager_load: bool) -> ckb_types::core::cell::CellStatus { + let _ = eager_load; + if let Some(data) = self.cell.get(out_point).cloned() { + ckb_types::core::cell::CellStatus::Live(data) + } else { + ckb_types::core::cell::CellStatus::Unknown + } + } +} + +impl ckb_types::core::cell::HeaderChecker for Resource { + fn check_valid(&self, _: &ckb_types::packed::Byte32) -> Result<(), ckb_types::core::error::OutPointError> { + Ok(()) + } +} + +#[derive(Clone, Default)] +pub struct Verifier {} + +impl Verifier { + pub fn verify_prior(&self, tx_resolved: &ckb_types::core::cell::ResolvedTransaction, _: &Resource) { + let a = tx_resolved.transaction.outputs().item_count(); + let b = tx_resolved.transaction.outputs_data().item_count(); + assert_eq!(a, b); + } + + pub fn verify( + &self, + tx_resolved: &ckb_types::core::cell::ResolvedTransaction, + dl: &Resource, + ) -> Result { + self.verify_prior(&tx_resolved, &dl); + let hardfork = ckb_types::core::hardfork::HardForks { + ckb2021: ckb_types::core::hardfork::CKB2021::new_mirana().as_builder().rfc_0032(10).build().unwrap(), + ckb2023: ckb_types::core::hardfork::CKB2023::new_mirana().as_builder().rfc_0049(20).build().unwrap(), + }; + let consensus = ckb_chain_spec::consensus::ConsensusBuilder::default().hardfork_switch(hardfork).build(); + let mut verifier = ckb_script::TransactionScriptsVerifier::new( + Arc::new(tx_resolved.clone()), + dl.clone(), + Arc::new(consensus), + Arc::new(ckb_script::TxVerifyEnv::new_commit( + &ckb_types::core::HeaderView::new_advanced_builder() + .epoch(ckb_types::core::EpochNumberWithFraction::new(10, 0, 1).pack()) + .build(), + )), + ); + verifier.set_debug_printer(|script: &ckb_types::packed::Byte32, msg: &str| { + let str = format!("Script({})", hex::encode(&script.as_slice()[..4])); + println!("{}: {}", str, msg); + }); + let result = verifier.verify(u64::MAX); + if result.is_ok() { + let cycles = (*result.as_ref().unwrap() as f64) / 1024.0 / 1024.0; + println!("cycles = {:.1} M ", cycles); + } + result + } +} + +#[derive(Clone, Default)] +pub struct Pickaxer { + outpoint_hash: ckb_types::packed::Byte32, + outpoint_i: u32, +} + +impl Pickaxer { + pub fn insert_cell_data(&mut self, dl: &mut Resource, data: &[u8]) -> ckb_types::core::cell::CellMeta { + let cell_out_point = ckb_types::packed::OutPoint::new(self.outpoint_hash.clone(), self.outpoint_i); + let cell_output = ckb_types::packed::CellOutput::new_builder() + .capacity(ckb_types::core::Capacity::bytes(0).unwrap().pack()) + .build(); + let cell_data = ckb_types::bytes::Bytes::copy_from_slice(data); + let cell_meta = ckb_types::core::cell::CellMetaBuilder::from_cell_output(cell_output, cell_data) + .out_point(cell_out_point.clone()) + .build(); + dl.cell.insert(cell_out_point.clone(), cell_meta.clone()); + self.outpoint_i += 1; + cell_meta + } + + pub fn insert_cell_fund( + &mut self, + dl: &mut Resource, + lock: ckb_types::packed::Script, + kype: Option, + data: &[u8], + ) -> ckb_types::core::cell::CellMeta { + let cell_out_point = ckb_types::packed::OutPoint::new(self.outpoint_hash.clone(), self.outpoint_i); + let cell_output = ckb_types::packed::CellOutput::new_builder() + .capacity(ckb_types::core::Capacity::bytes(0).unwrap().pack()) + .lock(lock) + .type_(ckb_types::packed::ScriptOpt::new_builder().set(kype).build()) + .build(); + let cell_data = ckb_types::bytes::Bytes::copy_from_slice(data); + let cell_meta = ckb_types::core::cell::CellMetaBuilder::from_cell_output(cell_output, cell_data) + .out_point(cell_out_point.clone()) + .build(); + dl.cell.insert(cell_out_point.clone(), cell_meta.clone()); + self.outpoint_i += 1; + cell_meta + } + + pub fn create_cell_dep(&self, cell_meta: &ckb_types::core::cell::CellMeta) -> ckb_types::packed::CellDep { + ckb_types::packed::CellDep::new_builder() + .out_point(cell_meta.out_point.clone()) + .dep_type(ckb_types::core::DepType::Code.into()) + .build() + } + + pub fn create_cell_input(&self, cell_meta: &ckb_types::core::cell::CellMeta) -> ckb_types::packed::CellInput { + ckb_types::packed::CellInput::new(cell_meta.out_point.clone(), 0) + } + + pub fn create_cell_output( + &self, + lock: ckb_types::packed::Script, + kype: Option, + ) -> ckb_types::packed::CellOutput { + ckb_types::packed::CellOutput::new_builder() + .capacity(ckb_types::core::Capacity::bytes(0).unwrap().pack()) + .lock(lock) + .type_(ckb_types::packed::ScriptOpt::new_builder().set(kype).build()) + .build() + } + + pub fn create_script(&self, cell_meta: &ckb_types::core::cell::CellMeta, args: &[u8]) -> ckb_types::packed::Script { + ckb_types::packed::Script::new_builder() + .args(args.pack()) + .code_hash(cell_meta.mem_cell_data_hash.clone().unwrap()) + .hash_type(ckb_types::core::ScriptHashType::Data1.into()) + .build() + } +} + +pub fn println_hex(name: &str, data: &[u8]) { + println!("Tester(........): {}(len={}): {}", name, data.len(), hex::encode(data)); +} + +pub fn println_log(data: &str) { + println!("Tester(........): {}", data); +} + +pub fn println_rtx(tx_resolved: &ckb_types::core::cell::ResolvedTransaction) { + let tx_json = ckb_jsonrpc_types::TransactionView::from(tx_resolved.transaction.clone()); + println!("Tester(........): {}", serde_json::to_string_pretty(&tx_json).unwrap()); +} + +static BINARY_ALWAYS_SUCCESS: &[u8] = include_bytes!("../../../build/always_success"); +static BINARY_OMNI_LOCK: &[u8] = include_bytes!("../../../build/omni_lock"); + +pub const IDENTITY_FLAGS_PUBKEY_HASH: u8 = 0; +pub const IDENTITY_FLAGS_ETHEREUM: u8 = 1; +pub const IDENTITY_FLAGS_BITCOIN: u8 = 4; +pub const IDENTITY_FLAGS_MULTISIG: u8 = 6; + +pub fn hash_blake160(message: &[u8]) -> Vec { + let r = ckb_hash::blake2b_256(message); + r[..20].to_vec() +} + +pub fn hash_keccak160(message: &[u8]) -> Vec { + hash_keccak256(message)[12..].to_vec() +} + +pub fn hash_keccak256(message: &[u8]) -> Vec { + use sha3::Digest; + let mut hasher = sha3::Keccak256::new(); + hasher.update(message); + let r = hasher.finalize(); + r.to_vec() +} + +pub fn hash_ripemd160_sha256(message: &[u8]) -> Vec { + return hash_ripemd160(&hash_sha256(message)); +} + +pub fn hash_ripemd160(message: &[u8]) -> Vec { + use ripemd::Digest; + let mut hasher = ripemd::Ripemd160::new(); + hasher.update(message); + hasher.finalize().to_vec() +} + +pub fn hash_sha256(message: &[u8]) -> Vec { + use sha2::Digest; + let mut hasher = sha2::Sha256::new(); + hasher.update(message); + hasher.finalize().to_vec() +} + +pub fn sign_bitcoin_p2pkh_compressed(prikey: ckb_crypto::secp::Privkey, message: &[u8]) -> Vec { + assert_eq!(message.len(), 32); + let sign = [ + vec![24], + b"Bitcoin Signed Message:\n".to_vec(), + vec![99], + b"CKB (Bitcoin Layer) transaction: 0x".to_vec(), + hex::encode(&message).as_bytes().to_vec(), + ]; + let sign = sign.concat(); + let sign = hash_sha256(&hash_sha256(&sign)); + let sign = prikey.sign_recoverable(&ckb_types::H256::from_slice(&sign).unwrap()).unwrap().serialize(); + let sign = [vec![sign[64] + 31], sign[..64].to_vec()].concat(); + sign +} + +pub fn sign_ethereum(prikey: ckb_crypto::secp::Privkey, message: &[u8]) -> Vec { + assert_eq!(message.len(), 32); + let sign = [b"\x19Ethereum Signed Message:\n32".to_vec(), message.to_vec()].concat(); + let sign = hash_keccak256(&sign); + let sign = ckb_types::H256::from_slice(&sign).unwrap(); + let sign = prikey.sign_recoverable(&sign).unwrap().serialize(); + sign +} + +pub fn sign_pubkey_hash(prikey: ckb_crypto::secp::Privkey, message: &[u8]) -> Vec { + assert_eq!(message.len(), 32); + let sign = ckb_types::H256::from_slice(message).unwrap(); + let sign = prikey.sign_recoverable(&sign).unwrap().serialize(); + sign +} + +pub fn cobuild_create_signing_message_hash_sighash_all( + tx: ckb_types::core::TransactionView, + dl: &Resource, + message: &schemas::basic::Message, +) -> Vec { + let mut hasher = blake2b_ref::Blake2bBuilder::new(32).personal(b"ckb-tcob-sighash").build(); + hasher.update(message.as_slice()); + hasher.update(tx.hash().as_slice()); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let input_cell_meta = dl.cell.get(&input_cell_out_point).unwrap(); + hasher.update(input_cell_meta.cell_output.as_slice()); + hasher.update(&(input_cell_meta.data_bytes as u32).to_le_bytes()); + hasher.update(&input_cell_meta.mem_cell_data.clone().unwrap()); + } + for witness in tx.witnesses().into_iter().skip(inputs_len) { + hasher.update(&(witness.len() as u32).to_le_bytes()); + hasher.update(&witness.raw_data()); + } + let mut result = vec![0u8; 32]; + hasher.finalize(&mut result); + result +} + +pub fn cobuild_create_signing_message_hash_sighash_all_only( + tx: ckb_types::core::TransactionView, + dl: &Resource, +) -> Vec { + let mut hasher = blake2b_ref::Blake2bBuilder::new(32).personal(b"ckb-tcob-sgohash").build(); + hasher.update(tx.hash().as_slice()); + let inputs_len = tx.inputs().len(); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let input_cell_meta = dl.cell.get(&input_cell_out_point).unwrap(); + hasher.update(input_cell_meta.cell_output.as_slice()); + hasher.update(&(input_cell_meta.data_bytes as u32).to_le_bytes()); + hasher.update(&input_cell_meta.mem_cell_data.clone().unwrap()); + } + for witness in tx.witnesses().into_iter().skip(inputs_len) { + hasher.update(&(witness.len() as u32).to_le_bytes()); + hasher.update(&witness.raw_data()); + } + let mut result = vec![0u8; 32]; + hasher.finalize(&mut result); + result +} + +pub fn cobuild_create_signing_message_hash_otx( + tx: ckb_types::core::TransactionView, + dl: &Resource, + message: &schemas::basic::Message, +) -> Vec { + let mut hasher = blake2b_ref::Blake2bBuilder::new(32).personal(b"ckb-tcob-otxhash").build(); + hasher.update(message.as_slice()); + let inputs_len = tx.inputs().len(); + hasher.update(&(inputs_len as u32).to_le_bytes()[..]); + for i in 0..inputs_len { + let input_cell = tx.inputs().get(i).unwrap(); + let input_cell_out_point = input_cell.previous_output(); + let input_cell_meta = dl.cell.get(&input_cell_out_point).unwrap(); + hasher.update(input_cell.as_slice()); + hasher.update(input_cell_meta.cell_output.as_slice()); + hasher.update(&(input_cell_meta.data_bytes as u32).to_le_bytes()); + hasher.update(&input_cell_meta.mem_cell_data.clone().unwrap()); + } + let outputs_len = tx.outputs().len(); + hasher.update(&(outputs_len as u32).to_le_bytes()[..]); + for i in 0..outputs_len { + let output_cell = tx.outputs().get(i).unwrap(); + let output_cell_data: Vec = tx.outputs_data().get(i).unwrap().unpack(); + hasher.update(output_cell.as_slice()); + hasher.update(&(output_cell_data.len() as u32).to_le_bytes()); + hasher.update(output_cell_data.as_slice()); + } + let cell_dep_len = tx.cell_deps().len(); + hasher.update(&(cell_dep_len as u32).to_le_bytes()[..]); + for i in 0..cell_dep_len { + let cell_dep = tx.cell_deps().get(i).unwrap(); + hasher.update(cell_dep.as_slice()); + } + let header_dep = tx.header_deps().len(); + hasher.update(&(header_dep as u32).to_le_bytes()[..]); + for i in 0..header_dep { + hasher.update(tx.header_deps().get(i).unwrap().as_slice()) + } + let mut result = vec![0u8; 32]; + hasher.finalize(&mut result); + result +} + +pub fn omnilock_create_witness_lock(sign: &[u8]) -> Vec { + omni_lock_test::omni_lock::OmniLockWitnessLock::new_builder() + .signature(Some(ckb_types::bytes::Bytes::copy_from_slice(sign)).pack()) + .build() + .as_slice() + .to_vec() +} + +const ERROR_TYPESCRIPT_MISSING: i8 = 116; +const ERROR_SEAL: i8 = 117; +const ERROR_FLOW: i8 = 118; +const ERROR_OTX_START_DUP: i8 = 119; +const ERROR_WRONG_OTX: i8 = 120; +const ERROR_MOL2_UNEXPECTED: i8 = 123; + +pub fn assert_script_error(err: ckb_error::Error, err_code: i8) { + let error_string = err.to_string(); + assert!( + error_string.contains(format!("error code {}", err_code).as_str()), + "error_string: {}, expected_error_code: {}", + error_string, + err_code + ); +} + +#[test] +fn test_cobuild_sighash_all_bitcoin_p2pkh_compressed() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000001"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_ripemd160_sha256(&pubkey.serialize()); + let args = [vec![IDENTITY_FLAGS_BITCOIN], pubkey_hash.to_vec(), vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(&mut dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_sighash_all(tx_builder.clone().build(), &dl, &msgs); + let sign = sign_bitcoin_p2pkh_compressed(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let sa = schemas::basic::SighashAll::new_builder().seal(seal.pack()).message(msgs).build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(sa).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + // Verify transaction + let tx = tx_builder.build(); + let tx_resolved = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx_resolved, &dl).unwrap(); +} + +#[test] +fn test_cobuild_sighash_all_only_ethereum() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000001"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_keccak160(&pubkey.as_ref()[..]); + let args = [vec![IDENTITY_FLAGS_ETHEREUM], pubkey_hash, vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(&mut dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output(px.create_script(&cell_meta_always_success, &[]), None)); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let sign = cobuild_create_signing_message_hash_sighash_all_only(tx_builder.clone().build(), &dl); + let sign = sign_ethereum(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let so = schemas::basic::SighashAllOnly::new_builder().seal(seal.pack()).build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(so).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + // Verify transaction + let tx = tx_builder.build(); + let tx_resolved = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx_resolved, &dl).unwrap(); +} + +#[test] +fn test_cobuild_otx_bitcoin_p2pkh_compressed() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000001"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_ripemd160_sha256(&pubkey.serialize()); + let args = [vec![IDENTITY_FLAGS_BITCOIN], pubkey_hash.to_vec(), vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(&mut dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let os = schemas::basic::OtxStart::new_builder().build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_otx(tx_builder.clone().build(), &dl, &msgs); + println_hex("smh", &sign); + let sign = sign_bitcoin_p2pkh_compressed(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let seal = schemas::basic::SealPair::new_builder() + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .seal(seal.pack()) + .build(); + let seal = schemas::basic::SealPairVec::new_builder().push(seal).build(); + let ox = schemas::basic::Otx::new_builder() + .seals(seal) + .message(msgs) + .input_cells(1u32.pack()) + .output_cells(1u32.pack()) + .cell_deps(2u32.pack()) + .header_deps(0u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(ox).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + // Verify transaction + let tx = tx_builder.build(); + let tx_resolved = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx_resolved, &dl).unwrap(); +} + +fn generate_otx_a0(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000001"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_ripemd160_sha256(&pubkey.serialize()); + let args = [vec![IDENTITY_FLAGS_BITCOIN], pubkey_hash.to_vec(), vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + let tx_builder = tx_builder + .header_dep(ckb_types::packed::Byte32::from_slice(&[11u8; 32]).unwrap()) + .header_dep(ckb_types::packed::Byte32::from_slice(&[12u8; 32]).unwrap()); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_otx(tx_builder.clone().build(), &dl, &msgs); + println_hex("smh", &sign); + let sign = sign_bitcoin_p2pkh_compressed(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let seal = schemas::basic::SealPair::new_builder() + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .seal(seal.pack()) + .build(); + let seal = schemas::basic::SealPairVec::new_builder().push(seal).build(); + let ox = schemas::basic::Otx::new_builder() + .seals(seal) + .message(msgs) + .input_cells(1u32.pack()) + .output_cells(1u32.pack()) + .cell_deps(2u32.pack()) + .header_deps(2u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(ox).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + tx_builder.build() +} + +fn generate_otx_b0(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000002"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_keccak160(&pubkey.as_ref()[..]); + let args = [vec![IDENTITY_FLAGS_ETHEREUM], pubkey_hash.to_vec(), vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + let tx_builder = tx_builder + .header_dep(ckb_types::packed::Byte32::from_slice(&[21u8; 32]).unwrap()) + .header_dep(ckb_types::packed::Byte32::from_slice(&[22u8; 32]).unwrap()); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_otx(tx_builder.clone().build(), &dl, &msgs); + println_hex("smh", &sign); + let sign = sign_ethereum(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let seal = schemas::basic::SealPair::new_builder() + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .seal(seal.pack()) + .build(); + let seal = schemas::basic::SealPairVec::new_builder().push(seal).build(); + let ox = schemas::basic::Otx::new_builder() + .seals(seal) + .message(msgs) + .input_cells(1u32.pack()) + .output_cells(1u32.pack()) + .cell_deps(2u32.pack()) + .header_deps(2u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(ox).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + tx_builder.build() +} + +fn generate_otx_c0(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = "0000000000000000000000000000000000000000000000000000000000000003"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_blake160(&pubkey.serialize()); + let args = [vec![IDENTITY_FLAGS_PUBKEY_HASH], pubkey_hash.to_vec(), vec![0x00]].concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_otx(tx_builder.clone().build(), &dl, &msgs); + println_hex("smh", &sign); + let sign = sign_pubkey_hash(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let seal = schemas::basic::SealPair::new_builder() + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .seal(seal.pack()) + .build(); + let seal = schemas::basic::SealPairVec::new_builder().push(seal).build(); + let ox = schemas::basic::Otx::new_builder() + .seals(seal) + .message(msgs) + .input_cells(1u32.pack()) + .output_cells(1u32.pack()) + .cell_deps(2u32.pack()) + .header_deps(0u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(ox).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + tx_builder.build() +} + +fn generate_otx_d0(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create prior knowledge + let prikey = vec![ + "0000000000000000000000000000000000000000000000000000000000000004", + "0000000000000000000000000000000000000000000000000000000000000005", + "0000000000000000000000000000000000000000000000000000000000000006", + ]; + let prikey: Vec = + prikey.iter().map(|e| ckb_crypto::secp::Privkey::from_str(e).unwrap()).collect(); + let pubkey: Vec = prikey.iter().map(|e| e.pubkey().unwrap()).collect(); + let pubkey_hash: Vec> = pubkey.iter().map(|e| hash_blake160(&e.serialize())).collect(); + let script = [vec![0, 0, 2, 3], pubkey_hash[0].clone(), pubkey_hash[1].clone(), pubkey_hash[2].clone()].concat(); + let script_hash = hash_blake160(&script); + let args = [vec![IDENTITY_FLAGS_MULTISIG], script_hash, vec![0x00]]; + let args = args.concat(); + + // Create cell meta + let cell_meta_always_success = px.insert_cell_data(dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + + // Create cell dep + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + + // Create input + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + + // Create output + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + + // Create output data + let tx_builder = tx_builder.output_data(Vec::new().pack()); + + // Create witness + let msgs = { + let action = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_always_success, &[]).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action2 = schemas::basic::Action::new_builder() + .script_info_hash(ckb_types::packed::Byte32::from_slice(&[0x00; 32]).unwrap()) + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .data(ckb_types::bytes::Bytes::from(vec![0x42; 128]).pack()) + .build(); + let action_vec = schemas::basic::ActionVec::new_builder().push(action).push(action2).build(); + let msgs = schemas::basic::Message::new_builder().actions(action_vec).build(); + msgs + }; + let sign = cobuild_create_signing_message_hash_otx(tx_builder.clone().build(), &dl, &msgs); + println_hex("smh", &sign); + let sign = { + let mut rets: Vec = vec![]; + rets.extend(script); + rets.extend(sign_pubkey_hash(prikey[0].clone(), &sign)); + rets.extend(sign_pubkey_hash(prikey[1].clone(), &sign)); + rets + }; + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let seal = schemas::basic::SealPair::new_builder() + .script_hash(px.create_script(&cell_meta_omni_lock, &args).calc_script_hash()) + .seal(seal.pack()) + .build(); + let seal = schemas::basic::SealPairVec::new_builder().push(seal).build(); + let ox = schemas::basic::Otx::new_builder() + .seals(seal) + .message(msgs) + .input_cells(1u32.pack()) + .output_cells(1u32.pack()) + .cell_deps(2u32.pack()) + .header_deps(0u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(ox).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + tx_builder.build() +} + +// Failed: No seal +fn generate_otx_a1_fail(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx = generate_otx_a0(dl, px); + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let witness = witnesses.get(0).unwrap(); + let mut otx = None; + let wl = schemas::top_level::WitnessLayout::from_slice(&witness.as_slice()[4..]).unwrap(); + match wl.as_reader().to_enum() { + schemas::top_level::WitnessLayoutUnionReader::Otx(otx_reader) => { + otx = Some( + schemas::basic::Otx::new_unchecked(otx_reader.as_slice().to_vec().into()) + .as_builder() + .seals(schemas::basic::SealPairVec::new_builder().build()) + .build(), + ); + } + _ => {} + }; + + assert!(otx.is_some()); + witnesses[0] = schemas::top_level::WitnessLayout::new_builder().set(otx.unwrap()).build().as_bytes().pack(); + + tx.as_advanced_builder().set_witnesses(witnesses).build() +} + +// Failed: The test_cobuild_otx_msg_flow is not 0 +fn generate_otx_a2_fail(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx = generate_otx_a0(dl, px); + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let witness = witnesses.get(0).unwrap(); + let mut otx = None; + + let wl = schemas::top_level::WitnessLayout::from_slice(&witness.as_slice()[4..]).unwrap(); + match wl.as_reader().to_enum() { + schemas::top_level::WitnessLayoutUnionReader::Otx(otx_reader) => { + let mut seal = otx_reader.seals().get(0).unwrap().seal().as_slice().to_vec(); + seal[0] = 0x22; + + let seal = + schemas::basic::SealPair::new_unchecked(otx_reader.seals().get(0).unwrap().as_slice().to_vec().into()) + .as_builder() + .seal(seal.pack()) + .build(); + + otx = Some( + schemas::basic::Otx::new_unchecked(otx_reader.as_slice().to_vec().into()) + .as_builder() + .seals(schemas::basic::SealPairVec::new_builder().push(seal).build()) + .build(), + ); + } + _ => {} + }; + + assert!(otx.is_some()); + witnesses[0] = schemas::top_level::WitnessLayout::new_builder().set(otx.unwrap()).build().as_bytes().pack(); + + tx.as_advanced_builder().set_witnesses(witnesses).build() +} + +// Failed: Message Action ScriptHash +fn generate_otx_a3_fail(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx = generate_otx_a0(dl, px); + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let witness = witnesses.get(0).unwrap(); + let mut otx = None; + let wl = schemas::top_level::WitnessLayout::from_slice(&witness.as_slice()[4..]).unwrap(); + match wl.as_reader().to_enum() { + schemas::top_level::WitnessLayoutUnionReader::Otx(otx_reader) => { + let cell_meta_always_success = px.insert_cell_data(dl, BINARY_ALWAYS_SUCCESS); + let hash = px.create_script(&cell_meta_always_success, &[]).calc_script_hash(); + let hash = hash.as_builder().nth0(0.into()).nth1(0.into()).nth2(0.into()).build(); + + let msg = schemas::basic::Message::new_unchecked(otx_reader.message().as_slice().to_vec().into()) + .as_builder() + .actions( + schemas::basic::ActionVec::new_builder() + .push( + schemas::basic::Action::new_unchecked( + otx_reader.message().actions().get(0).unwrap().as_slice().to_vec().into(), + ) + .as_builder() + .script_hash(hash) + .build(), + ) + .build(), + ) + .build(); + + otx = Some( + schemas::basic::Otx::new_unchecked(otx_reader.as_slice().to_vec().into()) + .as_builder() + .message(msg) + .build(), + ); + } + _ => {} + }; + + assert!(otx.is_some()); + witnesses[0] = schemas::top_level::WitnessLayout::new_builder().set(otx.unwrap()).build().as_bytes().pack(); + + tx.as_advanced_builder().set_witnesses(witnesses).build() +} + +// Failed: The intput cells/output cells/cell deps/header deps is 0 +fn generate_otx_a4_fail(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx = generate_otx_a0(dl, px); + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let witness = witnesses.get(0).unwrap(); + let mut otx = None; + let wl = schemas::top_level::WitnessLayout::from_slice(&witness.as_slice()[4..]).unwrap(); + match wl.as_reader().to_enum() { + schemas::top_level::WitnessLayoutUnionReader::Otx(otx_reader) => { + otx = Some( + schemas::basic::Otx::new_unchecked(otx_reader.as_slice().to_vec().into()) + .as_builder() + .input_cells(0u32.pack()) + .output_cells(0u32.pack()) + .cell_deps(0u32.pack()) + .header_deps(0u32.pack()) + .build(), + ); + } + _ => {} + }; + + assert!(otx.is_some()); + witnesses[0] = schemas::top_level::WitnessLayout::new_builder().set(otx.unwrap()).build().as_bytes().pack(); + + tx.as_advanced_builder().set_witnesses(witnesses).build() +} + +// Failed: None header and otx->header_deps not zero +fn generate_otx_a5_fail(dl: &mut Resource, px: &mut Pickaxer) -> ckb_types::core::TransactionView { + let tx = generate_otx_a0(dl, px); + tx.as_advanced_builder().set_header_deps(vec![]).build() +} + +fn assemble_otx(otxs: Vec) -> ckb_types::core::TransactionView { + let tx_builder = ckb_types::core::TransactionBuilder::default(); + let os = schemas::basic::OtxStart::new_builder().build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + let mut tx_builder = tx_builder.witness(wl.as_bytes().pack()); + for otx in otxs { + for e in otx.cell_deps_iter() { + tx_builder = tx_builder.cell_dep(e); + } + for e in otx.header_deps_iter() { + tx_builder = tx_builder.header_dep(e); + } + for e in otx.inputs().into_iter() { + tx_builder = tx_builder.input(e); + } + for e in otx.outputs().into_iter() { + tx_builder = tx_builder.output(e); + } + for e in otx.outputs_data().into_iter() { + tx_builder = tx_builder.output_data(e); + } + for e in otx.witnesses().into_iter() { + tx_builder = tx_builder.witness(e); + } + } + + tx_builder.build() +} + +fn merge_bytesvec::Item>>(v1: T1, v2: T1) -> Vec { + let v1: Vec = v1.into_iter().map(|f| f.into()).collect(); + let v2: Vec = v2.into_iter().map(|f| f.into()).collect(); + [v1, v2].concat() +} + +fn merge_tx( + tx1: ckb_types::core::TransactionView, + tx2: ckb_types::core::TransactionView, +) -> ckb_types::core::TransactionView { + let tx_builder = tx1.as_advanced_builder(); + tx_builder + .set_cell_deps(merge_bytesvec(tx1.cell_deps(), tx2.cell_deps())) + .set_header_deps(merge_bytesvec(tx1.header_deps(), tx2.header_deps())) + .set_inputs(merge_bytesvec(tx1.inputs(), tx2.inputs())) + .set_outputs(merge_bytesvec(tx1.outputs(), tx2.outputs())) + .set_witnesses(merge_bytesvec(tx1.witnesses(), tx2.witnesses())) + .set_outputs_data(merge_bytesvec(tx1.outputs_data(), tx2.outputs_data())) + .build() +} + +#[test] +fn test_cobuild_otx_simple() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx = assemble_otx(vec![generate_otx_a0(&mut dl, &mut px)]); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx, &dl).unwrap(); +} + +#[test] +fn test_cobuild_otx_prefix() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create otx prefix. Add a sighash all only cell for pay fees. + let prikey = "000000000000000000000000000000000000000000000000000000000000000f"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_keccak160(&pubkey.as_ref()[..]); + let args = [vec![IDENTITY_FLAGS_ETHEREUM], pubkey_hash, vec![0x00]].concat(); + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(&mut dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + let tx_builder = tx_builder.output(px.create_cell_output(px.create_script(&cell_meta_always_success, &[]), None)); + let tx_builder = tx_builder.output_data(Vec::new().pack()); + let tx_builder = tx_builder.witness(vec![0x00; 102].pack()); + + // Append otx + let os = schemas::basic::OtxStart::new_builder() + .start_cell_deps(2u32.pack()) + .start_header_deps(0u32.pack()) + .start_input_cell(1u32.pack()) + .start_output_cell(1u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + let mut tx_builder = tx_builder.witness(wl.as_bytes().pack()); + let otxs = vec![generate_otx_a0(&mut dl, &mut px), generate_otx_b0(&mut dl, &mut px)]; + for otx in otxs { + for e in otx.cell_deps_iter() { + tx_builder = tx_builder.cell_dep(e); + } + for e in otx.header_deps_iter() { + tx_builder = tx_builder.header_dep(e); + } + for e in otx.inputs().into_iter() { + tx_builder = tx_builder.input(e); + } + for e in otx.outputs().into_iter() { + tx_builder = tx_builder.output(e); + } + for e in otx.outputs_data().into_iter() { + tx_builder = tx_builder.output_data(e); + } + for e in otx.witnesses().into_iter() { + tx_builder = tx_builder.witness(e); + } + } + + // Create sign for prefix + let sign = cobuild_create_signing_message_hash_sighash_all_only(tx_builder.clone().build(), &dl); + println_hex("smh", &sign); + let sign = sign_ethereum(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let so = schemas::basic::SighashAllOnly::new_builder().seal(seal.pack()).build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(so).build(); + assert_eq!(wl.as_bytes().pack().len(), 102); + let mut wb = tx_builder.clone().build().witnesses().as_builder(); + wb.replace(0, wl.as_bytes().pack()); + let tx_builder = tx_builder.set_witnesses(wb.build().into_iter().collect()); + + let tx = tx_builder.build(); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx, &dl).unwrap(); +} + +#[test] +fn test_cobuild_otx_prefix_and_suffix() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let tx_builder = ckb_types::core::TransactionBuilder::default(); + + // Create otx prefix + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_always_success, &[]), None, &[]); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + let tx_builder = tx_builder.output(px.create_cell_output( + px.create_script(&cell_meta_always_success, &[]), + Some(px.create_script(&cell_meta_always_success, &[])), + )); + let tx_builder = tx_builder.output_data(vec![].pack()); + + // Append otx + let os = schemas::basic::OtxStart::new_builder() + .start_cell_deps(1u32.pack()) + .start_header_deps(0u32.pack()) + .start_input_cell(1u32.pack()) + .start_output_cell(1u32.pack()) + .build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + let mut tx_builder = tx_builder.witness(wl.as_bytes().pack()); + let otxs = vec![generate_otx_a0(&mut dl, &mut px), generate_otx_b0(&mut dl, &mut px)]; + for otx in otxs { + for e in otx.cell_deps_iter() { + tx_builder = tx_builder.cell_dep(e); + } + for e in otx.header_deps_iter() { + tx_builder = tx_builder.header_dep(e); + } + for e in otx.inputs().into_iter() { + tx_builder = tx_builder.input(e); + } + for e in otx.outputs().into_iter() { + tx_builder = tx_builder.output(e); + } + for e in otx.outputs_data().into_iter() { + tx_builder = tx_builder.output_data(e); + } + for e in otx.witnesses().into_iter() { + tx_builder = tx_builder.witness(e); + } + } + + // Create otx suffix. Add a sighash all only cell for pay fees. + let prikey = "000000000000000000000000000000000000000000000000000000000000000f"; + let prikey = ckb_crypto::secp::Privkey::from_str(prikey).unwrap(); + let pubkey = prikey.pubkey().unwrap(); + let pubkey_hash = hash_keccak160(&pubkey.as_ref()[..]); + let args = [vec![IDENTITY_FLAGS_ETHEREUM], pubkey_hash, vec![0x00]].concat(); + let cell_meta_always_success = px.insert_cell_data(&mut dl, BINARY_ALWAYS_SUCCESS); + let cell_meta_omni_lock = px.insert_cell_data(&mut dl, BINARY_OMNI_LOCK); + let cell_meta_i = px.insert_cell_fund(&mut dl, px.create_script(&cell_meta_omni_lock, &args), None, &[]); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_always_success)); + let tx_builder = tx_builder.cell_dep(px.create_cell_dep(&cell_meta_omni_lock)); + let tx_builder = tx_builder.input(px.create_cell_input(&cell_meta_i)); + let tx_builder = tx_builder.output(px.create_cell_output(px.create_script(&cell_meta_always_success, &[]), None)); + let tx_builder = tx_builder.output_data(Vec::new().pack()); + let sign = cobuild_create_signing_message_hash_sighash_all_only(tx_builder.clone().build(), &dl); + let sign = sign_ethereum(prikey, &sign); + let sign = omnilock_create_witness_lock(&sign); + let seal = [vec![0x00], sign].concat(); + println_hex("seal", seal.as_slice()); + let so = schemas::basic::SighashAllOnly::new_builder().seal(seal.pack()).build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(so).build(); + let tx_builder = tx_builder.witness(wl.as_bytes().pack()); + + let tx = tx_builder.build(); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + let cycles = verifier.verify(&tx, &dl).unwrap(); + assert!(cycles < 5_000_000); +} + +#[test] +fn test_cobuild_otx_random() { + type Fntype = dyn Fn(&mut Resource, &mut Pickaxer) -> ckb_types::core::TransactionView; + let mut rgen = rand::prelude::thread_rng(); + let mut success_set = Vec::<(&str, Box)>::new(); + success_set.push(("a0", Box::new(generate_otx_a0))); + success_set.push(("b0", Box::new(generate_otx_b0))); + success_set.push(("c0", Box::new(generate_otx_c0))); + success_set.push(("d0", Box::new(generate_otx_d0))); + for i in 0..success_set.len() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + println_log(format!("case: {}", success_set[i].0).as_str()); + let tx = assemble_otx(vec![success_set[i].1(&mut dl, &mut px)]); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx, &dl).unwrap(); + } + for _ in 0..32 { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let mut hint = vec![]; + let mut data = vec![]; + for _ in 0..2 + (rgen.next_u32() as usize % 3) { + let nf = success_set.choose(&mut rgen).unwrap(); + hint.push(nf.0); + data.push(nf.1(&mut dl, &mut px)); + } + println_log(format!("case: {}", hint.join(" + ")).as_str()); + let tx = assemble_otx(data); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + verifier.verify(&tx, &dl).unwrap(); + } + + // Failed + // Compared with success_set, Error code is added + let mut failed_set = Vec::<(&str, Box, i8)>::new(); + failed_set.push(("a1", Box::new(generate_otx_a1_fail), ERROR_SEAL)); + failed_set.push(("a2", Box::new(generate_otx_a2_fail), ERROR_FLOW)); + failed_set.push(("a3", Box::new(generate_otx_a3_fail), ERROR_TYPESCRIPT_MISSING)); + failed_set.push(("a4", Box::new(generate_otx_a4_fail), ERROR_WRONG_OTX)); + failed_set.push(("a5", Box::new(generate_otx_a5_fail), ERROR_MOL2_UNEXPECTED)); + + for i in 0..failed_set.len() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + println_log(format!("case: {}", failed_set[i].0).as_str()); + let tx = assemble_otx(vec![failed_set[i].1(&mut dl, &mut px)]); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + assert_script_error(verifier.verify(&tx, &dl).unwrap_err(), failed_set[i].2); + } + + // n success + 1 failed + for _ in 0..32 { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let mut hint = vec![]; + let mut data = vec![]; + for _ in 0..2 + (rgen.next_u32() as usize % 3) { + let nf = success_set.choose(&mut rgen).unwrap(); + hint.push(nf.0); + data.push(nf.1(&mut dl, &mut px)); + } + + let nf = failed_set.choose(&mut rgen).unwrap(); + hint.push(nf.0); + data.push(nf.1(&mut dl, &mut px)); + + // println_log(format!("case: {}", hint.join(" + ")).as_str()); + let tx = assemble_otx(data); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + assert_script_error(verifier.verify(&tx, &dl).unwrap_err(), nf.2); + } + + // n success + n failed. + // unknow error code + for _ in 0..32 { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + let mut hint = vec![]; + let mut data = vec![]; + for _ in 0..2 + (rgen.next_u32() as usize % 3) { + let nf = success_set.choose(&mut rgen).unwrap(); + hint.push(nf.0); + data.push(nf.1(&mut dl, &mut px)); + } + + for _ in 0..2 + (rgen.next_u32() as usize % 3) { + let nf = failed_set.choose(&mut rgen).unwrap(); + hint.push(nf.0); + data.push(nf.1(&mut dl, &mut px)); + } + + // println_log(format!("case: {}", hint.join(" + ")).as_str()); + let tx = assemble_otx(data); + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + let error_code = verifier.verify(&tx, &dl).unwrap_err(); + println!("random multi failed, error code: {}", error_code); + } +} + +#[test] +fn test_cobuild_otx_double_otx_start() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + + let tx = assemble_otx(vec![generate_otx_a0(&mut dl, &mut px)]); + + let tx = { + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let os = schemas::basic::OtxStart::new_builder().build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + witnesses.insert(0, wl.as_bytes().pack()); + + tx.as_advanced_builder().set_witnesses(witnesses).build() + }; + + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + assert_script_error(verifier.verify(&tx, &dl).unwrap_err(), ERROR_OTX_START_DUP); +} + +#[test] +fn test_cobuild_otx_noexistent_otx_id() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + + let tx = assemble_otx(vec![generate_otx_a0(&mut dl, &mut px)]); + let tx = { + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + + let os = schemas::basic::OtxStart::new_builder().build(); + let wl = schemas::top_level::WitnessLayout::new_builder().set(os).build(); + witnesses.insert(0, wl.as_bytes().pack()); + + tx.as_advanced_builder().set_witnesses(witnesses).build() + }; + + let mut witnesses: Vec = tx.witnesses().into_iter().map(|f| f).collect(); + let mut witness = witnesses.get(1).unwrap().as_slice().to_vec(); + witness[4..8].copy_from_slice(&(4278190084u32 + 2).to_le_bytes()); // WitnessLayoutOtxStart + 1 + witnesses[1] = witness.pack(); + + let tx = tx.as_advanced_builder().set_witnesses(witnesses).build(); + + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + let result_verifier = verifier.verify(&tx, &dl); + assert_script_error(result_verifier.unwrap_err(), ERROR_WRONG_OTX); +} + +#[test] +fn test_cobuild_otx_double_input() { + let mut dl = Resource::default(); + let mut px = Pickaxer::default(); + + let tx = merge_tx( + assemble_otx(vec![generate_otx_a0(&mut dl, &mut px)]), + assemble_otx(vec![generate_otx_a0(&mut dl, &mut px)]), + ); + + let tx = ckb_types::core::cell::resolve_transaction(tx, &mut HashSet::new(), &dl, &dl).unwrap(); + let verifier = Verifier::default(); + assert_script_error(verifier.verify(&tx, &dl).unwrap_err(), ERROR_OTX_START_DUP); +} diff --git a/tests/omni_lock_rust/tests/test_secp256k1_compatibility.rs b/tests/omni_lock_rust/tests/test_secp256k1_compatibility.rs index 08e358a..4580049 100644 --- a/tests/omni_lock_rust/tests/test_secp256k1_compatibility.rs +++ b/tests/omni_lock_rust/tests/test_secp256k1_compatibility.rs @@ -8,9 +8,7 @@ use ckb_script::{ScriptError, TransactionScriptsVerifier, TxVerifyEnv}; use ckb_types::{ bytes::Bytes, bytes::BytesMut, - core::{ - cell::ResolvedTransaction, hardfork::HardForkSwitch, EpochNumberWithFraction, HeaderView, - }, + core::{cell::ResolvedTransaction, EpochNumberWithFraction, HeaderView}, packed::WitnessArgs, prelude::*, H256, @@ -19,10 +17,9 @@ use lazy_static::lazy_static; use rand::{thread_rng, Rng, SeedableRng}; use misc::{ - assert_script_error, blake160, build_resolved_tx, debug_printer, gen_tx, - gen_tx_with_grouped_args, gen_witness_lock, sign_tx, sign_tx_by_input_group, sign_tx_hash, - DummyDataLoader, TestConfig, TestScheme, ERROR_ENCODING, ERROR_PUBKEY_BLAKE160_HASH, - ERROR_WITNESS_SIZE, IDENTITY_FLAGS_PUBKEY_HASH, MAX_CYCLES, + assert_script_error, blake160, build_resolved_tx, debug_printer, gen_tx, gen_tx_with_grouped_args, + gen_witness_lock, sign_tx, sign_tx_by_input_group, sign_tx_hash, verify_tx, DummyDataLoader, TestConfig, + TestScheme, ERROR_ENCODING, ERROR_PUBKEY_BLAKE160_HASH, ERROR_WITNESS_SIZE, IDENTITY_FLAGS_PUBKEY_HASH, MAX_CYCLES, }; mod misc; @@ -39,13 +36,10 @@ fn test_sighash_all_unlock() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); + println!("cycles = {}", verify_result.clone().unwrap()); verify_result.expect("pass verification"); } @@ -59,11 +53,7 @@ fn test_sighash_all_unlock_with_args() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -88,11 +78,7 @@ fn test_sighash_all_with_extra_witness_unlock() { let tx = sign_tx(&mut data_loader, tx.clone(), &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader.clone()); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } @@ -108,17 +94,10 @@ fn test_sighash_all_with_extra_witness_unlock() { .build() }) .unwrap(); - let tx = tx - .as_advanced_builder() - .set_witnesses(vec![wrong_witness.as_bytes().pack()]) - .build(); + let tx = tx.as_advanced_builder().set_witnesses(vec![wrong_witness.as_bytes().pack()]).build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader.clone()); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -136,11 +115,7 @@ fn test_sighash_all_with_grouped_inputs_unlock() { let tx = sign_tx(&mut data_loader, tx.clone(), &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader.clone()); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } @@ -158,18 +133,11 @@ fn test_sighash_all_with_grouped_inputs_unlock() { .unwrap(); let tx = tx .as_advanced_builder() - .set_witnesses(vec![ - tx.witnesses().get(0).unwrap(), - wrong_witness.as_bytes().pack(), - ]) + .set_witnesses(vec![tx.witnesses().get(0).unwrap(), wrong_witness.as_bytes().pack()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -191,10 +159,7 @@ fn test_sighash_all_with_2_different_inputs_unlock() { let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); } @@ -211,10 +176,7 @@ fn test_signing_with_wrong_key() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -234,10 +196,7 @@ fn test_signing_wrong_tx_hash() { }; let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -253,11 +212,7 @@ fn test_super_long_witness() { let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); verify_result.expect("pass verification"); @@ -283,11 +238,7 @@ fn test_sighash_all_2_in_2_out_cycles() { let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); let cycles = verify_result.expect("pass verification"); @@ -315,17 +266,11 @@ fn test_sighash_all_witness_append_junk_data() { witness.push(0); witnesses[0] = witness.into(); - let tx = tx - .as_advanced_builder() - .set_witnesses(witnesses.into_iter().map(|w| w.pack()).collect()) - .build(); + let tx = tx.as_advanced_builder().set_witnesses(witnesses.into_iter().map(|w| w.pack()).collect()).build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -350,25 +295,16 @@ fn test_sighash_all_witness_args_ambiguity() { // move data from input_type to output_type let witness = WitnessArgs::new_unchecked(witness); let data = witness.input_type().clone(); - witness - .as_builder() - .output_type(data) - .input_type(Some(Bytes::new()).pack()) - .build() + witness.as_builder().output_type(data).input_type(Some(Bytes::new()).pack()).build() }) .collect(); - let tx = tx - .as_advanced_builder() - .set_witnesses(witnesses.into_iter().map(|w| w.as_bytes().pack()).collect()) - .build(); + let tx = + tx.as_advanced_builder().set_witnesses(witnesses.into_iter().map(|w| w.as_bytes().pack()).collect()).build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -387,11 +323,7 @@ fn test_sighash_all_witnesses_ambiguity() { let witness = Unpack::>::unpack(&tx.witnesses()).remove(0); let tx = tx .as_advanced_builder() - .set_witnesses(vec![ - witness.pack(), - Bytes::new().pack(), - Bytes::from(vec![42]).pack(), - ]) + .set_witnesses(vec![witness.pack(), Bytes::new().pack(), Bytes::from(vec![42]).pack()]) .build(); let tx = sign_tx_by_input_group(&mut data_loader, tx, 0, 3, &mut config); @@ -399,20 +331,13 @@ fn test_sighash_all_witnesses_ambiguity() { let witness = Unpack::>::unpack(&tx.witnesses()).remove(0); let tx = tx .as_advanced_builder() - .set_witnesses(vec![ - witness.pack(), - Bytes::from(vec![42]).pack(), - Bytes::new().pack(), - ]) + .set_witnesses(vec![witness.pack(), Bytes::from(vec![42]).pack(), Bytes::new().pack()]) .build(); assert_eq!(tx.witnesses().len(), tx.inputs().len()); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(MAX_CYCLES); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } @@ -426,11 +351,7 @@ fn test_sighash_all_cover_extra_witnesses() { let witness = Unpack::>::unpack(&tx.witnesses()).remove(0); let tx = tx .as_advanced_builder() - .set_witnesses(vec![ - witness.pack(), - Bytes::from(vec![42]).pack(), - Bytes::new().pack(), - ]) + .set_witnesses(vec![witness.pack(), Bytes::from(vec![42]).pack(), Bytes::new().pack()]) .build(); let tx = sign_tx_by_input_group(&mut data_loader, tx, 0, 3, &mut config); assert!(tx.witnesses().len() > tx.inputs().len()); @@ -439,19 +360,12 @@ fn test_sighash_all_cover_extra_witnesses() { let mut witnesses = Unpack::>::unpack(&tx.witnesses()); let tx = tx .as_advanced_builder() - .set_witnesses(vec![ - witnesses.remove(0).pack(), - witnesses.remove(1).pack(), - Bytes::from(vec![0]).pack(), - ]) + .set_witnesses(vec![witnesses.remove(0).pack(), witnesses.remove(1).pack(), Bytes::from(vec![0]).pack()]) .build(); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let verifier = TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let verifier = verify_tx(resolved_tx, data_loader); let verify_result = verifier.verify(60000000); assert_script_error(verify_result.unwrap_err(), ERROR_PUBKEY_BLAKE160_HASH) } diff --git a/tests/omni_lock_rust/tests/test_sudt_supply.rs b/tests/omni_lock_rust/tests/test_sudt_supply.rs index 7473287..ebe9aa6 100644 --- a/tests/omni_lock_rust/tests/test_sudt_supply.rs +++ b/tests/omni_lock_rust/tests/test_sudt_supply.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -use ckb_script::TransactionScriptsVerifier; use ckb_types::{ bytes::Bytes, core::{Capacity, DepType, ScriptHashType, TransactionView}, @@ -10,10 +9,9 @@ use ckb_types::{ use rand::{thread_rng, Rng}; use misc::{ - assert_script_error, build_always_success_script, build_resolved_tx, debug_printer, gen_tx, - sign_tx, DummyDataLoader, EthereumConfig, TestConfig, ALWAYS_SUCCESS, CKB_INVALID_DATA, - ERROR_BURN, ERROR_EXCEED_SUPPLY, ERROR_NO_INFO_CELL, ERROR_SUPPLY_AMOUNT, - IDENTITY_FLAGS_ETHEREUM, MAX_CYCLES, SIMPLE_UDT, + assert_script_error, build_always_success_script, build_resolved_tx, debug_printer, gen_tx, sign_tx, verify_tx, + DummyDataLoader, EthereumConfig, TestConfig, ALWAYS_SUCCESS, CKB_INVALID_DATA, ERROR_BURN, ERROR_EXCEED_SUPPLY, + ERROR_NO_INFO_CELL, ERROR_SUPPLY_AMOUNT, IDENTITY_FLAGS_ETHEREUM, MAX_CYCLES, SIMPLE_UDT, }; mod misc; @@ -25,7 +23,7 @@ fn gen_info_cell_type_script() -> (Script, [u8; 32]) { rng.fill(&mut args[..]); let script = Script::new_builder() .code_hash(data_hash.clone()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data1.into()) .args(Bytes::from(args).pack()) .build(); let script_hash = script.calc_script_hash(); @@ -46,15 +44,12 @@ fn gen_out_point() -> OutPoint { fn sudt_type_script(loader: &DummyDataLoader, tx: &TransactionView) -> Script { let omni_lock_out_point = tx.inputs().get(0).unwrap().previous_output(); - let omni_lock_hash = loader - .cells - .get(&omni_lock_out_point) - .map(|(output, _)| output.lock().calc_script_hash()) - .unwrap(); + let omni_lock_hash = + loader.cells.get(&omni_lock_out_point).map(|(output, _)| output.lock().calc_script_hash()).unwrap(); let data_hash = CellOutput::calc_data_hash(&SIMPLE_UDT); Script::new_builder() .code_hash(data_hash.clone()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data1.into()) .args(omni_lock_hash.as_bytes().pack()) .build() } @@ -72,50 +67,27 @@ fn add_sudt_to_inputs( .build(); let previous_data = Bytes::from(amount.to_le_bytes().to_vec()); let previous_out_point = gen_out_point(); - loader - .cells - .insert(previous_out_point.clone(), (previous_output, previous_data)); - tx.as_advanced_builder() - .input(CellInput::new(previous_out_point, 0)) - .build() + loader.cells.insert(previous_out_point.clone(), (previous_output, previous_data)); + tx.as_advanced_builder().input(CellInput::new(previous_out_point, 0)).build() } -fn add_sudt_to_outputs( - sudt_type_script: Script, - tx: TransactionView, - amount: u128, -) -> TransactionView { +fn add_sudt_to_outputs(sudt_type_script: Script, tx: TransactionView, amount: u128) -> TransactionView { let output = CellOutput::new_builder() .capacity(42.pack()) .type_(Some(sudt_type_script).pack()) .lock(build_always_success_script()) .build(); let data = Bytes::from(amount.to_le_bytes().to_vec()); - tx.as_advanced_builder() - .output(output) - .output_data(data.pack()) - .build() + tx.as_advanced_builder().output(output).output_data(data.pack()).build() } fn add_sudt_dep(loader: &mut DummyDataLoader, tx: TransactionView) -> TransactionView { let dep_out_point = gen_out_point(); - let sudt_cell = CellOutput::new_builder() - .capacity( - Capacity::bytes(SIMPLE_UDT.len()) - .expect("script capacity") - .pack(), - ) - .build(); - loader - .cells - .insert(dep_out_point.clone(), (sudt_cell, SIMPLE_UDT.clone())); + let sudt_cell = + CellOutput::new_builder().capacity(Capacity::bytes(SIMPLE_UDT.len()).expect("script capacity").pack()).build(); + loader.cells.insert(dep_out_point.clone(), (sudt_cell, SIMPLE_UDT.clone())); tx.as_advanced_builder() - .cell_dep( - CellDep::new_builder() - .out_point(dep_out_point) - .dep_type(DepType::Code.into()) - .build(), - ) + .cell_dep(CellDep::new_builder().out_point(dep_out_point).dep_type(DepType::Code.into()).build()) .build() } @@ -132,35 +104,20 @@ fn add_info_cell_to_inputs( .build(); let previous_data = Bytes::from(data); let previous_out_point = gen_out_point(); - loader - .cells - .insert(previous_out_point.clone(), (previous_output, previous_data)); - tx.as_advanced_builder() - .input(CellInput::new(previous_out_point, 0)) - .build() + loader.cells.insert(previous_out_point.clone(), (previous_output, previous_data)); + tx.as_advanced_builder().input(CellInput::new(previous_out_point, 0)).build() } -fn add_info_cell_to_outputs( - type_script: Script, - tx: TransactionView, - data: Vec, -) -> TransactionView { +fn add_info_cell_to_outputs(type_script: Script, tx: TransactionView, data: Vec) -> TransactionView { let output = CellOutput::new_builder() .capacity(42.pack()) .type_(Some(type_script).pack()) .lock(build_always_success_script()) .build(); - tx.as_advanced_builder() - .output(output) - .output_data(Bytes::from(data).pack()) - .build() + tx.as_advanced_builder().output(output).output_data(Bytes::from(data).pack()).build() } -fn build_info_cell_data( - current_supply: u128, - max_supply: u128, - sudt_type_script_hash: &[u8], -) -> Vec { +fn build_info_cell_data(current_supply: u128, max_supply: u128, sudt_type_script_hash: &[u8]) -> Vec { let version = 0u8; let mut data = vec![0u8; 1 + 16 + 16 + 32]; data[0] = version; @@ -182,11 +139,7 @@ where let tx = sign_tx(&mut data_loader, tx, &mut config); let resolved_tx = build_resolved_tx(&data_loader, &tx); - let consensus = misc::gen_consensus(); - let tx_env = misc::gen_tx_env(); - let mut verifier = - TransactionScriptsVerifier::new(&resolved_tx, &consensus, &data_loader, &tx_env); - + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); verifier.set_debug_printer(debug_printer); let verify_result = verifier.verify(MAX_CYCLES); if error_code == 0 { @@ -210,19 +163,10 @@ fn test_success_issue_token() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -242,16 +186,9 @@ fn test_burn_token() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_inputs(data_loader, sudt_type_script.clone(), tx, 200); - let input_info_cell_data = - build_info_cell_data(400, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = - build_info_cell_data(200, max_supply, sudt_type_script_hash.as_slice()); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(400, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = build_info_cell_data(200, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -271,11 +208,8 @@ fn test_no_info_cell_in_inputs() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -295,14 +229,8 @@ fn test_no_info_cell_in_outputs() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx }); } @@ -323,25 +251,11 @@ fn test_too_many_info_cell_in_inputs() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data.clone(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data.clone()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -363,24 +277,11 @@ fn test_too_many_info_cell_in_outputs() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); - tx = add_info_cell_to_outputs( - info_cell_type_script.clone(), - tx, - output_info_cell_data.clone(), - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); + tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data.clone()); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -400,21 +301,12 @@ fn test_info_cell_size_not_enough() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let mut input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let mut input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); input_info_cell_data.truncate(input_info_cell_data.len() - 1); output_info_cell_data.truncate(output_info_cell_data.len() - 1); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -436,16 +328,9 @@ fn test_sudt_amount_overflow() { tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, 20); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, u128::max_value() - 10); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = - build_info_cell_data(40, max_supply, sudt_type_script_hash.as_slice()); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = build_info_cell_data(40, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -465,19 +350,10 @@ fn test_input_exceed_supply() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(6001, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 6001 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(6001, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(6001 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -496,19 +372,10 @@ fn test_output_exceed_supply() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -528,19 +395,10 @@ fn test_wrong_supply_delta() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let output_info_cell_data = build_info_cell_data( - 20 + issue_amount + 2, - max_supply, - sudt_type_script_hash.as_slice(), - ); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount + 2, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -560,21 +418,12 @@ fn test_info_cell_wrong_version() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let mut input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let mut input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); input_info_cell_data[0] = 3; output_info_cell_data[0] = 3; - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -594,21 +443,12 @@ fn test_info_cell_version_not_match() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let mut input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let mut input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); input_info_cell_data[0] = 0; output_info_cell_data[0] = 3; - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -628,20 +468,11 @@ fn test_info_cell_length_not_match() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); output_info_cell_data.extend(vec![0u8; 4]); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -661,21 +492,12 @@ fn test_info_cell_extra_data_changed() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let mut input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let mut input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); input_info_cell_data.extend(vec![0u8; 4]); output_info_cell_data.extend(vec![1u8; 4]); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx }); @@ -695,20 +517,98 @@ fn test_info_cell_max_supply_changed() { let sudt_type_script_hash = sudt_type_script.calc_script_hash(); tx = add_sudt_dep(data_loader, tx); tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); - let input_info_cell_data = - build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); - let mut output_info_cell_data = build_info_cell_data( - 20 + issue_amount, - max_supply, - sudt_type_script_hash.as_slice(), - ); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let mut output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); output_info_cell_data[17..17 + 16].copy_from_slice(&(max_supply + 3).to_le_bytes()[..]); - tx = add_info_cell_to_inputs( - data_loader, - info_cell_type_script.clone(), - tx, - input_info_cell_data, - ); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); + tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); + tx + }); +} + +fn run_sudt_supply_case_cobuild(error_code: i8, gen_tx_fn: F) +where + F: Fn(&mut DummyDataLoader, &mut TestConfig) -> TransactionView, +{ + let mut data_loader = DummyDataLoader::new(); + let mut config = TestConfig::new(IDENTITY_FLAGS_ETHEREUM, false); + config.cobuild_enabled = true; + config.set_chain_config(Box::new(EthereumConfig::default())); + + let tx = gen_tx_fn(&mut data_loader, &mut config); + let tx = sign_tx(&mut data_loader, tx, &mut config); + let resolved_tx = build_resolved_tx(&data_loader, &tx); + + let mut verifier = verify_tx(resolved_tx, data_loader.clone()); + verifier.set_debug_printer(debug_printer); + let verify_result = verifier.verify(MAX_CYCLES); + if error_code == 0 { + verify_result.expect("pass verification"); + } else { + assert_script_error(verify_result.unwrap_err(), error_code); + } +} + +// ==== SUCCESS cases ==== +#[test] +fn test_cobuild_success_issue_token() { + run_sudt_supply_case_cobuild(0, |data_loader, config| { + let (info_cell_type_script, cell_id) = gen_info_cell_type_script(); + config.set_sudt_supply(cell_id); + + let mut tx = gen_tx(data_loader, config); + let issue_amount: u128 = 336; + let max_supply: u128 = 6000; + let sudt_type_script = sudt_type_script(data_loader, &tx); + let sudt_type_script_hash = sudt_type_script.calc_script_hash(); + tx = add_sudt_dep(data_loader, tx); + tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); + let input_info_cell_data = build_info_cell_data(20, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); + tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); + tx + }); +} + +// ==== ERROR cases ==== +#[test] +fn test_cobuild_burn_token() { + run_sudt_supply_case_cobuild(ERROR_BURN, |data_loader, config| { + let (info_cell_type_script, cell_id) = gen_info_cell_type_script(); + config.set_sudt_supply(cell_id); + + let mut tx = gen_tx(data_loader, config); + let max_supply: u128 = 6000; + let sudt_type_script = sudt_type_script(data_loader, &tx); + let sudt_type_script_hash = sudt_type_script.calc_script_hash(); + tx = add_sudt_dep(data_loader, tx); + tx = add_sudt_to_inputs(data_loader, sudt_type_script.clone(), tx, 200); + let input_info_cell_data = build_info_cell_data(400, max_supply, sudt_type_script_hash.as_slice()); + let output_info_cell_data = build_info_cell_data(200, max_supply, sudt_type_script_hash.as_slice()); + tx = add_info_cell_to_inputs(data_loader, info_cell_type_script.clone(), tx, input_info_cell_data); + tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); + tx + }); +} + +#[test] +fn test_cobuild_no_info_cell_in_inputs() { + run_sudt_supply_case_cobuild(ERROR_NO_INFO_CELL, |data_loader, config| { + let (info_cell_type_script, cell_id) = gen_info_cell_type_script(); + config.set_sudt_supply(cell_id); + + let mut tx = gen_tx(data_loader, config); + let issue_amount: u128 = 336; + let max_supply: u128 = 6000; + let sudt_type_script = sudt_type_script(data_loader, &tx); + let sudt_type_script_hash = sudt_type_script.calc_script_hash(); + tx = add_sudt_dep(data_loader, tx); + tx = add_sudt_to_outputs(sudt_type_script.clone(), tx, issue_amount); + let output_info_cell_data = + build_info_cell_data(20 + issue_amount, max_supply, sudt_type_script_hash.as_slice()); tx = add_info_cell_to_outputs(info_cell_type_script.clone(), tx, output_info_cell_data); tx });