-
Notifications
You must be signed in to change notification settings - Fork 16
/
ckb_utils.h
130 lines (119 loc) · 3.85 KB
/
ckb_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
utils.h
Defines basic utility functions.
*/
#ifndef CKB_C_STDLIB_CKB_UTILS_H_
#define CKB_C_STDLIB_CKB_UTILS_H_
#include "stddef.h"
/* 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 ckb_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;
}
}
}
#define CKB_SINCE_VALUE_BITS 56
#define CKB_SINCE_VALUE_MASK 0x00ffffffffffffff
#define CKB_SINCE_FLAG_METRIC_MASK 0b01100000
#define CKB_SINCE_EPOCH_FRACTION_FLAG 0b00100000
/*
* Compare since, comparable is set to 1 when the
* a and b since values have the same flags, otherwise comparable is set to 0.
*
* Return value only has meaning when the comparable is set to 1:
* 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 ckb_since_cmp(uint64_t a, uint64_t b, int *comparable) {
uint8_t a_flag = a >> CKB_SINCE_VALUE_BITS;
uint8_t b_flag = b >> CKB_SINCE_VALUE_BITS;
if (a_flag != b_flag) {
*comparable = 0;
return 0;
}
*comparable = 1;
if ((a_flag & CKB_SINCE_FLAG_METRIC_MASK) == CKB_SINCE_EPOCH_FRACTION_FLAG) {
return ckb_epoch_number_with_fraction_cmp(a, b);
} else {
uint64_t a_value = a & CKB_SINCE_VALUE_MASK;
uint64_t b_value = b & CKB_SINCE_VALUE_MASK;
if (a_value < b_value) {
return -1;
} else if (a_value > b_value) {
return 1;
} else {
return 0;
}
}
}
/*
* A temporal patch to solve https://github.com/nervosnetwork/ckb-vm/issues/97.
* If you use a ckb-vm >= 0.20.x, you can safely ignore it. A common practice
* is that use CKB_SP_ALIGN in the first line of the main(), and then use
* CKB_SP_ALIGN_END before exiting.
*
* Example:
* int main() {
* CKB_SP_ALIGN;
* ...
* if cond {
* CKB_SP_ALIGN_END;
* return 1;
* }
* ...
* CKB_SP_ALIGN_END;
* return 0;
* }
*/
#define CKB_SP_ALIGN \
__asm__( \
"addi t0, sp, 0\n" \
"andi sp, sp, 0xfffffffffffffff8\n" \
"sd t0, -8(sp)\n" \
"sd t0, -16(sp)\n" \
"addi sp, sp, -8\n" \
"andi sp, sp, 0xfffffffffffffff0" \
: \
: \
: "t0")
#define CKB_SP_ALIGN_END __asm__("ld sp, 0(sp)")
#endif /* CKB_C_STDLIB_CKB_UTILS_H_ */