Skip to content

Commit b452f1e

Browse files
author
Cedric
committed
remove debuginfo in ckb-libc
1 parent d901f1a commit b452f1e

File tree

2 files changed

+224
-1
lines changed

2 files changed

+224
-1
lines changed

Makefile

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ clean:
1010
# rm -rf internal/parser
1111
# rm -rf internal/lexer
1212
rm -rf output
13+
rm third-party/ckb-c-stdlib/*.o
14+
rm third-party/ckb-c-stdlib/*.a
1315
grammar: antlr
1416

1517
antlr:
@@ -20,6 +22,7 @@ fmt:
2022
cd ${MKFILE_DIR} && go fmt ./...
2123
build:
2224
@echo "build"
25+
make clean
2326
git submodule update --init --recursive
2427
make ckb-libc
2528
go build -v -trimpath \
@@ -29,6 +32,20 @@ build:
2932
build/debug:
3033
go build -gcflags=all="-N -l" ./cmd/cell
3134
ckb-libc: ckb-libc-release
35+
sudt-c:
36+
@echo " >>> build sudt-c"
37+
cd third-party/ckb-c-stdlib && \
38+
clang --target=riscv64 \
39+
-march=rv64imc \
40+
-nostdlib \
41+
-Wall -Werror -Wextra -Wno-unused-parameter -Wno-nonnull -fno-builtin-printf -fno-builtin-memcmp -O3 -fdata-sections -ffunction-sections \
42+
-I libc \
43+
-I molecule \
44+
-I . \
45+
../sudt.c \
46+
-o sudt-c && \
47+
cp sudt-c ../..
48+
@echo "sussecfully build sudt-c"
3249
ckb-libc-debug:
3350
@echo " >>> build libdummy-debug.a"
3451
cd third-party/ckb-c-stdlib && \
@@ -49,7 +66,7 @@ ckb-libc-release:
4966
cd third-party/ckb-c-stdlib && \
5067
clang --target=riscv64 \
5168
-march=rv64imc \
52-
-Wall -Werror -Wextra -Wno-unused-parameter -Wno-nonnull -fno-builtin-printf -fno-builtin-memcmp -O3 -g -fdata-sections -ffunction-sections \
69+
-Wall -Werror -Wextra -Wno-unused-parameter -Wno-nonnull -fno-builtin-printf -fno-builtin-memcmp -O3 -fdata-sections -ffunction-sections \
5370
-I libc \
5471
-I . \
5572
-c ../wrapper.c && \
@@ -77,6 +94,7 @@ test/example:
7794
${CELL} -t riscv tests/examples/cell-data.cell && ckb-debugger --bin cell-data
7895
${CELL} -t riscv tests/examples/inputs.cell && ckb-debugger --bin inputs
7996
${CELL} -t riscv tests/examples/outputs.cell && ckb-debugger --bin outputs
97+
${CELL} -t riscv tests/examples/sudt.cell && ckb-debugger --bin sudt
8098

8199
${CELL} -t riscv tests/examples/multi-files && ckb-debugger --bin multi-files
82100
${CELL} -t riscv tests/examples/import-package && ckb-debugger --bin import-package

third-party/sudt.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// # Simple UDT
2+
//
3+
// A simple UDT script using 128 bit unsigned integer range
4+
//
5+
// This UDT has 2 unlocking modes:
6+
//
7+
// 1. If one of the transaction input has a lock script matching the UDT
8+
// script argument, the UDT script will be in owner mode. In owner mode no
9+
// checks is performed, the owner can perform any operations such as issuing
10+
// more UDTs or burning UDTs. By ensuring at least one transaction input has
11+
// a matching lock script, the ownership of UDT can be ensured.
12+
// 2. Otherwise, the UDT script will be in normal mode, where it ensures the
13+
// sum of all input tokens is not smaller than the sum of all output tokens.
14+
//
15+
// Notice one caveat of this UDT script is that only one UDT can be issued
16+
// for each unique lock script. A more sophisticated UDT script might include
17+
// other arguments(such as the hash of the first input) as a unique identifier,
18+
// however for the sake of simplicity, we are happy with this limitation.
19+
20+
// First, let's include header files used to interact with CKB.
21+
#if defined(CKB_SIMULATOR)
22+
#include "ckb_syscall_simulator.h"
23+
#else
24+
#include "ckb_syscalls.h"
25+
#endif
26+
#include "blockchain.h"
27+
28+
// We are limiting the script size loaded to be 32KB at most. This should be
29+
// more than enough. We are also using blake2b with 256-bit hash here, which is
30+
// the same as CKB.
31+
#define BLAKE2B_BLOCK_SIZE 32
32+
#define SCRIPT_SIZE 32768
33+
34+
// Common error codes that might be returned by the script.
35+
#define ERROR_ARGUMENTS_LEN -1
36+
#define ERROR_ENCODING -2
37+
#define ERROR_SYSCALL -3
38+
#define ERROR_SCRIPT_TOO_LONG -21
39+
#define ERROR_OVERFLOWING -51
40+
#define ERROR_AMOUNT -52
41+
42+
// We will leverage gcc's 128-bit integer extension here for number crunching.
43+
typedef unsigned __int128 uint128_t;
44+
45+
#ifdef CKB_SIMULATOR
46+
int simulator_main() {
47+
#else
48+
int main() {
49+
#endif
50+
// First, let's load current running script, so we can extract owner lock
51+
// script hash from script args.
52+
unsigned char script[SCRIPT_SIZE];
53+
uint64_t len = SCRIPT_SIZE;
54+
int ret = ckb_load_script(script, &len, 0);
55+
if (ret != CKB_SUCCESS) {
56+
return ERROR_SYSCALL;
57+
}
58+
if (len > SCRIPT_SIZE) {
59+
return ERROR_SCRIPT_TOO_LONG;
60+
}
61+
mol_seg_t script_seg;
62+
script_seg.ptr = (uint8_t *)script;
63+
script_seg.size = len;
64+
65+
if (MolReader_Script_verify(&script_seg, false) != MOL_OK) {
66+
return ERROR_ENCODING;
67+
}
68+
69+
mol_seg_t args_seg = MolReader_Script_get_args(&script_seg);
70+
mol_seg_t args_bytes_seg = MolReader_Bytes_raw_bytes(&args_seg);
71+
if (args_bytes_seg.size != BLAKE2B_BLOCK_SIZE) {
72+
return ERROR_ARGUMENTS_LEN;
73+
}
74+
75+
// With owner lock script extracted, we will look through each input in the
76+
// current transaction to see if any unlocked cell uses owner lock.
77+
int owner_mode = 0;
78+
size_t i = 0;
79+
while (1) {
80+
uint8_t buffer[BLAKE2B_BLOCK_SIZE];
81+
uint64_t len = BLAKE2B_BLOCK_SIZE;
82+
// There are 2 points worth mentioning here:
83+
//
84+
// * First, we are using the checked version of CKB syscalls, the checked
85+
// versions will return an error if our provided buffer is not enough to
86+
// hold all returned data. This can help us ensure that we are processing
87+
// enough data here.
88+
// * Second, `CKB_CELL_FIELD_LOCK_HASH` is used here to directly load the
89+
// lock script hash, so we don't have to manually calculate the hash again
90+
// here.
91+
ret = ckb_checked_load_cell_by_field(buffer, &len, 0, i, CKB_SOURCE_INPUT,
92+
CKB_CELL_FIELD_LOCK_HASH);
93+
if (ret == CKB_INDEX_OUT_OF_BOUND) {
94+
break;
95+
}
96+
if (ret != CKB_SUCCESS) {
97+
return ret;
98+
}
99+
if (len != BLAKE2B_BLOCK_SIZE) {
100+
return ERROR_ENCODING;
101+
}
102+
if (memcmp(buffer, args_bytes_seg.ptr, BLAKE2B_BLOCK_SIZE) == 0) {
103+
owner_mode = 1;
104+
break;
105+
}
106+
i += 1;
107+
}
108+
109+
// When owner mode is triggered, we won't perform any checks here, the owner
110+
// is free to make any changes here, including token issurance, minting, etc.
111+
if (owner_mode) {
112+
return CKB_SUCCESS;
113+
}
114+
115+
// When the owner mode is not enabled, however, we will then need to ensure
116+
// the sum of all input tokens is not smaller than the sum of all output
117+
// tokens. First, let's loop through all input cells containing current UDTs,
118+
// and gather the sum of all input tokens.
119+
uint128_t input_amount = 0;
120+
i = 0;
121+
while (1) {
122+
uint128_t current_amount = 0;
123+
len = 16;
124+
// The implementation here does not require that the transaction only
125+
// contains UDT cells for the current UDT type. It's perfectly fine to mix
126+
// the cells for multiple different types of UDT together in one
127+
// transaction. But that also means we need a way to tell one UDT type from
128+
// another UDT type. The trick is in the `CKB_SOURCE_GROUP_INPUT` value used
129+
// here. When using it as the source part of the syscall, the syscall would
130+
// only iterate through cells with the same script as the current running
131+
// script. Since different UDT types will naturally have different
132+
// script(the args part will be different), we can be sure here that this
133+
// loop would only iterate through UDTs that are of the same type as the one
134+
// identified by the current running script.
135+
//
136+
// In the case that multiple UDT types are included in the same transaction,
137+
// this simple UDT script will be run multiple times to validate the
138+
// transaction, each time with a different script containing different
139+
// script args, representing different UDT types.
140+
//
141+
// A different trick used here, is that our current implementation assumes
142+
// that the amount of UDT is stored as unsigned 128-bit little endian
143+
// integer in the first 16 bytes of cell data. Since RISC-V also uses little
144+
// endian format, we can just read the first 16 bytes of cell data into
145+
// `current_amount`, which is just an unsigned 128-bit integer in C. The
146+
// memory layout of a C program will ensure that the value is set correctly.
147+
ret = ckb_load_cell_data((uint8_t *)&current_amount, &len, 0, i,
148+
CKB_SOURCE_GROUP_INPUT);
149+
// When `CKB_INDEX_OUT_OF_BOUND` is reached, we know we have iterated
150+
// through all cells of current type.
151+
if (ret == CKB_INDEX_OUT_OF_BOUND) {
152+
break;
153+
}
154+
if (ret != CKB_SUCCESS) {
155+
return ret;
156+
}
157+
if (len < 16) {
158+
return ERROR_ENCODING;
159+
}
160+
input_amount += current_amount;
161+
// Like any serious smart contract out there, we will need to check for
162+
// overflows.
163+
if (input_amount < current_amount) {
164+
return ERROR_OVERFLOWING;
165+
}
166+
i += 1;
167+
}
168+
169+
// With the sum of all input UDT tokens gathered, let's now iterate through
170+
// output cells to grab the sum of all output UDT tokens.
171+
uint128_t output_amount = 0;
172+
i = 0;
173+
while (1) {
174+
uint128_t current_amount = 0;
175+
len = 16;
176+
// Similar to the above code piece, we are also looping through output cells
177+
// with the same script as current running script here by using
178+
// `CKB_SOURCE_GROUP_OUTPUT`.
179+
ret = ckb_load_cell_data((uint8_t *)&current_amount, &len, 0, i,
180+
CKB_SOURCE_GROUP_OUTPUT);
181+
if (ret == CKB_INDEX_OUT_OF_BOUND) {
182+
break;
183+
}
184+
if (ret != CKB_SUCCESS) {
185+
return ret;
186+
}
187+
if (len < 16) {
188+
return ERROR_ENCODING;
189+
}
190+
output_amount += current_amount;
191+
// Like any serious smart contract out there, we will need to check for
192+
// overflows.
193+
if (output_amount < current_amount) {
194+
return ERROR_OVERFLOWING;
195+
}
196+
i += 1;
197+
}
198+
199+
// When both value are gathered, we can perform the final check here to
200+
// prevent non-authorized token issurance.
201+
if (input_amount < output_amount) {
202+
return ERROR_AMOUNT;
203+
}
204+
return CKB_SUCCESS;
205+
}

0 commit comments

Comments
 (0)