Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <stdbool.h>
26 : #include <string.h>
27 :
28 : #include "runtime.h"
29 : #include "defs.h"
30 : #include "err.h"
31 : #include "hal/log.h"
32 : #include "nvm.h"
33 : #include "memutil.h"
34 :
35 : #include "bc_state.h"
36 : #include "bc_err.h"
37 :
38 : #include "mem.h"
39 :
40 : // -----------------------------------------------------------------------
41 : // Blockchain state initialization
42 : // -----------------------------------------------------------------------
43 :
44 : // Here we take it from an external definition (see Makefile for details)
45 : #if (defined(HSM_PLATFORM_LEDGER) || defined(HSM_PLATFORM_SGX)) && \
46 : defined(PARAM_INITIAL_BLOCK_HASH)
47 : static const uint8_t INITIAL_BLOCK_HASH[] = PARAM_INITIAL_BLOCK_HASH;
48 : #elif defined(HSM_PLATFORM_X86)
49 : uint8_t INITIAL_BLOCK_HASH[HASH_LENGTH];
50 : #else
51 : #error "Initial block hash not defined!"
52 : #endif
53 :
54 : /*
55 : * Initialize blockchain state.
56 : */
57 2 : void bc_init_state() {
58 2 : if (!N_bc_state.initialized) {
59 1 : NVM_RESET(&N_bc_state, sizeof(N_bc_state));
60 1 : NVM_WRITE(N_bc_state.best_block, INITIAL_BLOCK_HASH, HASH_SIZE);
61 1 : NVM_WRITE(N_bc_state.newest_valid_block, INITIAL_BLOCK_HASH, HASH_SIZE);
62 :
63 1 : uint8_t t = 1;
64 1 : NVM_WRITE(&N_bc_state.initialized, &t, sizeof(t));
65 : }
66 :
67 2 : explicit_bzero(&bc_st_updating, sizeof(bc_st_updating));
68 2 : if (N_bc_state_updating_backup.valid) {
69 0 : uint8_t f = 0;
70 0 : NVM_WRITE(&N_bc_state_updating_backup.valid, &f, sizeof(f));
71 0 : SAFE_MEMMOVE(&bc_st_updating,
72 : sizeof(bc_st_updating),
73 : MEMMOVE_ZERO_OFFSET,
74 : &N_bc_state_updating_backup.data,
75 : sizeof(N_bc_state_updating_backup.data),
76 : MEMMOVE_ZERO_OFFSET,
77 : sizeof(N_bc_state_updating_backup.data),
78 : { return; });
79 : }
80 : }
81 :
82 : /**
83 : * Backup the current partial advance blockchain state
84 : * to NVM
85 : */
86 0 : void bc_backup_partial_state() {
87 : bc_state_updating_backup_t backup;
88 :
89 0 : if (bc_st_updating.in_progress) {
90 0 : backup.valid = 1;
91 0 : SAFE_MEMMOVE(&backup.data,
92 : sizeof(backup.data),
93 : MEMMOVE_ZERO_OFFSET,
94 : &bc_st_updating,
95 : sizeof(bc_st_updating),
96 : MEMMOVE_ZERO_OFFSET,
97 : sizeof(bc_st_updating),
98 : { return; });
99 :
100 0 : NVM_WRITE(&N_bc_state_updating_backup,
101 : &backup,
102 : sizeof(N_bc_state_updating_backup));
103 : }
104 : }
105 :
106 : // -----------------------------------------------------------------------
107 : // Blockchain state operations
108 : // -----------------------------------------------------------------------
109 :
110 : // Non-volatile blockchain validation state
111 : NON_VOLATILE bc_state_t N_bc_state_var;
112 :
113 : // Non-volatile intermediate advance blockchain state backup
114 : NON_VOLATILE bc_state_updating_backup_t N_bc_state_updating_backup_var;
115 :
116 : /*
117 : * Dump hash corresponding to hash_codes[hash_ix] to APDU.
118 : * @ret size of data dumped to APDU buffer
119 : */
120 154 : uint8_t dump_hash(uint8_t hash_code) {
121 : const uint8_t* h;
122 154 : switch (hash_code) {
123 22 : case BEST_BLOCK:
124 22 : h = N_bc_state.best_block;
125 22 : break;
126 22 : case NEWEST_VALID_BLOCK:
127 22 : h = N_bc_state.newest_valid_block;
128 22 : break;
129 22 : case ANCESTOR_BLOCK:
130 22 : h = N_bc_state.ancestor_block;
131 22 : break;
132 22 : case ANCESTOR_RECEIPT_ROOT:
133 22 : h = N_bc_state.ancestor_receipt_root;
134 22 : break;
135 22 : case U_BEST_BLOCK:
136 22 : h = bc_st_updating.best_block;
137 22 : break;
138 22 : case U_NEWEST_VALID_BLOCK:
139 22 : h = bc_st_updating.newest_valid_block;
140 22 : break;
141 22 : case U_NEXT_EXPECTED_BLOCK:
142 22 : h = bc_st_updating.next_expected_block;
143 22 : break;
144 0 : default:
145 0 : FAIL(PROT_INVALID);
146 : }
147 :
148 154 : APDU_DATA_PTR[0] = hash_code;
149 308 : SAFE_MEMMOVE(APDU_DATA_PTR,
150 : APDU_TOTAL_DATA_SIZE_OUT,
151 : 1,
152 : h,
153 : HASH_SIZE,
154 : MEMMOVE_ZERO_OFFSET,
155 : HASH_SIZE,
156 : FAIL(PROT_INVALID));
157 :
158 154 : return 1 + HASH_SIZE;
159 : }
160 :
161 : /*
162 : * Dump difficulty to the APDU buffer. This function will copy to the
163 : * the buffer the bytes comprising the state's cumulative difficulty
164 : * in big endian order, with no leading zeroes.
165 : *
166 : * @ret number of bytes dumped to APDU buffer
167 : */
168 800 : uint8_t dump_difficulty() {
169 : uint8_t buf[sizeof(bc_st_updating.total_difficulty)];
170 22 : dump_bigint_be(buf, bc_st_updating.total_difficulty, BIGINT_LEN);
171 22 : unsigned int start = 0;
172 800 : for (; start < sizeof(buf) && buf[start] == 0; start++)
173 778 : continue;
174 44 : SAFE_MEMMOVE(APDU_DATA_PTR,
175 : APDU_TOTAL_DATA_SIZE_OUT,
176 : MEMMOVE_ZERO_OFFSET,
177 : buf,
178 : sizeof(buf),
179 : start,
180 : sizeof(buf) - start,
181 : FAIL(PROT_INVALID));
182 22 : return sizeof(buf) - start;
183 : }
184 :
185 : /*
186 : * Dump initial block hash to the specified APDU buffer data offset.
187 : *
188 : * @arg[in] offset APDU buffer data dump offset
189 : * @ret number of bytes dumped to APDU buffer
190 : */
191 1 : uint8_t bc_dump_initial_block_hash(int offset) {
192 2 : SAFE_MEMMOVE(APDU_DATA_PTR,
193 : APDU_TOTAL_DATA_SIZE_OUT,
194 : offset,
195 : INITIAL_BLOCK_HASH,
196 : sizeof(INITIAL_BLOCK_HASH),
197 : MEMMOVE_ZERO_OFFSET,
198 : sizeof(INITIAL_BLOCK_HASH),
199 : FAIL(PROT_INVALID));
200 1 : return sizeof(INITIAL_BLOCK_HASH);
201 : }
202 :
203 : /*
204 : * Dump blockchain state flags to APDU buffer.
205 : * @ret number of bytes dumped to buffer
206 : */
207 22 : uint8_t dump_flags() {
208 22 : APDU_DATA_PTR[0] = bc_st_updating.in_progress;
209 22 : APDU_DATA_PTR[1] = bc_st_updating.already_validated;
210 22 : APDU_DATA_PTR[2] = bc_st_updating.found_best_block;
211 22 : return 3;
212 : }
213 :
214 : /*
215 : * Implement the get blockchain state procotol.
216 : *
217 : * @arg[in] rx number of received bytes from the Host
218 : * @ret number of transmited bytes to the host
219 : */
220 198 : unsigned int bc_get_state(volatile unsigned int rx) {
221 198 : uint8_t op = APDU_OP();
222 :
223 198 : uint8_t expected_data_size = op == OP_STATE_GET_HASH ? 1 : 0;
224 198 : if (APDU_DATA_SIZE(rx) != expected_data_size) {
225 0 : FAIL(PROT_INVALID);
226 : }
227 :
228 198 : if (op == OP_STATE_GET_HASH) {
229 154 : return TX_FOR_DATA_SIZE(dump_hash(APDU_DATA_PTR[0]));
230 : }
231 :
232 44 : if (op == OP_STATE_GET_DIFF) {
233 22 : return TX_FOR_DATA_SIZE(dump_difficulty());
234 : }
235 :
236 22 : if (op == OP_STATE_GET_FLAGS) {
237 22 : return TX_FOR_DATA_SIZE(dump_flags());
238 : }
239 :
240 0 : FAIL(PROT_INVALID);
241 : return 0;
242 : }
243 :
244 : /*
245 : * Implement the reset blockchain state protocol.
246 : *
247 : * @arg[in] rx number of received bytes from the Host
248 : * @ret number of transmited bytes to the host
249 : */
250 17 : unsigned int bc_reset_state(volatile unsigned int rx) {
251 17 : if (APDU_OP() != OP_STATE_RESET_INIT) {
252 0 : FAIL(PROT_INVALID);
253 : }
254 17 : if (APDU_DATA_SIZE(rx) != 0) {
255 0 : FAIL(PROT_INVALID);
256 : }
257 17 : RESET_BC_STATE();
258 17 : SET_APDU_OP(OP_STATE_RESET_DONE);
259 17 : return TX_NO_DATA();
260 : }
|