solana.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. #include <stdint.h>
  2. #include <stddef.h>
  3. #include "stdlib.h"
  4. #include "solana_sdk.h"
  5. extern uint64_t solang_dispatch(const SolParameters *param);
  6. // The address 'SysvarC1ock11111111111111111111111111111111' base58 decoded
  7. static const SolPubkey clock_address = {0x06, 0xa7, 0xd5, 0x17, 0x18, 0xc7, 0x74, 0xc9, 0x28, 0x56, 0x63, 0x98, 0x69, 0x1d, 0x5e, 0xb6, 0x8b, 0x5e, 0xb8, 0xa3, 0x9b, 0x4b, 0x6d, 0x5c, 0x73, 0x55, 0x5b, 0x21, 0x00, 0x00, 0x00, 0x00};
  8. // The address '11111111111111111111111111111111' base58 decoded
  9. static const SolPubkey system_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  10. uint64_t
  11. entrypoint(const uint8_t *input)
  12. {
  13. SolParameters params;
  14. uint64_t ret = sol_deserialize(input, &params);
  15. if (ret)
  16. {
  17. return ret;
  18. }
  19. int account_no;
  20. params.ka_clock = NULL;
  21. params.ka_cur = UINT64_MAX;
  22. for (account_no = 0; account_no < params.ka_num; account_no++)
  23. {
  24. const SolAccountInfo *acc = &params.ka[account_no];
  25. if (SolPubkey_same(params.account_id, acc->key))
  26. {
  27. params.ka_cur = account_no;
  28. }
  29. else if (SolPubkey_same(&clock_address, acc->key))
  30. {
  31. params.ka_clock = acc;
  32. }
  33. }
  34. if (params.ka_cur == UINT64_MAX)
  35. {
  36. return ERROR_INVALID_INSTRUCTION_DATA;
  37. }
  38. return solang_dispatch(&params);
  39. }
  40. void *__malloc(uint32_t size)
  41. {
  42. return sol_alloc_free_(size, NULL);
  43. }
  44. uint64_t sol_invoke_signed_c(
  45. const SolInstruction *instruction,
  46. const SolAccountInfo *account_infos,
  47. int account_infos_len,
  48. const SolSignerSeeds *signers_seeds,
  49. int signers_seeds_len);
  50. uint64_t external_call(uint8_t *input, uint32_t input_len, SolParameters *params)
  51. {
  52. // The first 32 bytes of the input is the destination address
  53. const SolPubkey *dest = (const SolPubkey *)input;
  54. SolAccountMeta metas[10];
  55. SolInstruction instruction = {
  56. .program_id = NULL,
  57. .accounts = metas,
  58. .account_len = params->ka_num,
  59. .data = input,
  60. .data_len = input_len,
  61. };
  62. for (int account_no = 0; account_no < params->ka_num; account_no++)
  63. {
  64. const SolAccountInfo *acc = &params->ka[account_no];
  65. if (SolPubkey_same(dest, acc->key))
  66. {
  67. instruction.program_id = acc->owner;
  68. params->ka_last_called = acc;
  69. }
  70. metas[account_no].pubkey = acc->key;
  71. metas[account_no].is_writable = acc->is_writable;
  72. metas[account_no].is_signer = acc->is_signer;
  73. }
  74. if (instruction.program_id)
  75. {
  76. return sol_invoke_signed_c(&instruction, params->ka, params->ka_num, NULL, 0);
  77. }
  78. else
  79. {
  80. sol_log("call to account not in transaction");
  81. return ERROR_INVALID_ACCOUNT_DATA;
  82. }
  83. }
  84. // This function creates a new address and calls its constructor.
  85. uint64_t create_contract(uint8_t *input, uint32_t input_len, uint64_t lamports, uint64_t space, SolParameters *params)
  86. {
  87. SolAccountInfo *new_acc = NULL;
  88. const SolSignerSeed *seed = NULL;
  89. // find a suitable new account and seed
  90. for (int i = 0; i < params->seeds_len; i++)
  91. {
  92. SolAccountInfo *acc = &params->ka[i];
  93. if (acc->data_len == 0 && SolPubkey_same(&system_address, acc->owner))
  94. {
  95. new_acc = acc;
  96. seed = &params->seeds[i];
  97. }
  98. }
  99. if (!new_acc)
  100. {
  101. sol_log("create contract requires a new account");
  102. return ERROR_NEW_ACCOUNT_NEEDED;
  103. }
  104. SolAccountMeta create_metas[2] = {
  105. {params->account_id, true, true},
  106. {new_acc->key, true, true},
  107. };
  108. // FIXME we need to add our own seed if we have one in order to fund/approve it
  109. SolSignerSeeds signer_seeds[1] = {
  110. {seed, 1},
  111. };
  112. // create the account
  113. struct create_account
  114. {
  115. uint32_t instruction;
  116. uint64_t lamports;
  117. uint64_t space;
  118. SolPubkey owner;
  119. } __attribute__((__packed__)) create_account = {
  120. 0,
  121. lamports,
  122. space,
  123. *params->ka[params->ka_cur].owner,
  124. };
  125. const SolInstruction create_instruction = {
  126. .program_id = (SolPubkey *)&system_address,
  127. .accounts = create_metas,
  128. .account_len = SOL_ARRAY_SIZE(create_metas),
  129. .data = (uint8_t *)&create_account,
  130. .data_len = sizeof(create_account),
  131. };
  132. uint64_t ret = sol_invoke_signed_c(&create_instruction, params->ka, params->ka_num,
  133. signer_seeds, SOL_ARRAY_SIZE(signer_seeds));
  134. if (ret != 0)
  135. {
  136. sol_log("failed to create new account");
  137. sol_panic();
  138. }
  139. // Our new account now has some space
  140. new_acc->data_len = space;
  141. SolAccountMeta metas[10];
  142. const SolInstruction instruction = {
  143. .program_id = (SolPubkey *)params->program_id,
  144. .accounts = metas,
  145. .account_len = params->ka_num,
  146. .data = input,
  147. .data_len = input_len,
  148. };
  149. // A fresh account must be provided by the caller; find it
  150. for (int account_no = 0; account_no < params->ka_num; account_no++)
  151. {
  152. const SolAccountInfo *acc = &params->ka[account_no];
  153. metas[account_no].pubkey = acc->key;
  154. metas[account_no].is_writable = acc->is_writable;
  155. metas[account_no].is_signer = acc->is_signer;
  156. }
  157. params->ka_last_called = new_acc;
  158. __memcpy8(input, new_acc->key->x, SIZE_PUBKEY / 8);
  159. __memcpy8(input + SIZE_PUBKEY, params->account_id->x, SIZE_PUBKEY / 8);
  160. return sol_invoke_signed_c(&instruction, params->ka, params->ka_num, NULL, 0);
  161. }
  162. struct clock_layout
  163. {
  164. uint64_t slot;
  165. uint64_t epoch_start_timestamp;
  166. uint64_t epoch;
  167. uint64_t leader_schedule_epoch;
  168. uint64_t unix_timestamp;
  169. };
  170. uint64_t sol_timestamp(SolParameters *params)
  171. {
  172. if (!params->ka_clock)
  173. {
  174. sol_log("clock account missing from transaction");
  175. sol_panic();
  176. }
  177. struct clock_layout *clock_data = (struct clock_layout *)params->ka_clock->data;
  178. return clock_data->unix_timestamp;
  179. }
  180. struct account_data_header
  181. {
  182. uint32_t magic;
  183. uint32_t returndata_len;
  184. uint32_t returndata_offset;
  185. uint32_t heap_offset;
  186. };
  187. // Simple heap for account data
  188. //
  189. // The heap is a doubly-linked list of objects, so we can merge with neighbours when we free.
  190. // We should use offsets rather than pointers as the layout in memory will be different each
  191. // time it is called.
  192. // We don't expect the account data to exceed 4GB so we use 32 bit offsets.
  193. // The account data can grow so the last entry always has length = 0 and offset_next = 0.
  194. struct chunk
  195. {
  196. uint32_t offset_next, offset_prev;
  197. uint32_t length;
  198. uint32_t allocated;
  199. };
  200. #define ROUND_UP(n, d) (((n) + (d)-1) & ~(d - 1))
  201. uint64_t account_data_alloc(SolAccountInfo *ai, uint32_t size, uint32_t *res)
  202. {
  203. void *data = ai->data;
  204. struct account_data_header *hdr = data;
  205. if (!size)
  206. {
  207. *res = 0;
  208. return 0;
  209. }
  210. uint32_t offset = hdr->heap_offset;
  211. uint32_t alloc_size = ROUND_UP(size, 8);
  212. uint32_t offset_prev = 0;
  213. for (;;)
  214. {
  215. struct chunk *chunk = data + offset;
  216. if (!chunk->allocated)
  217. {
  218. if (!chunk->length)
  219. {
  220. offset += sizeof(struct chunk);
  221. if (offset + alloc_size + sizeof(struct chunk) >= ai->data_len)
  222. {
  223. return ERROR_ACCOUNT_DATA_TOO_SMALL;
  224. }
  225. chunk->offset_next = offset + alloc_size;
  226. chunk->offset_prev = offset_prev;
  227. chunk->allocated = true;
  228. chunk->length = size;
  229. struct chunk *next = data + chunk->offset_next;
  230. next->offset_prev = offset - sizeof(struct chunk);
  231. next->length = 0;
  232. next->offset_next = 0;
  233. next->allocated = false;
  234. *res = offset;
  235. return 0;
  236. }
  237. else if (chunk->length < alloc_size)
  238. {
  239. // too small
  240. }
  241. else if (alloc_size + sizeof(struct chunk) + 8 > chunk->length)
  242. {
  243. // just right
  244. chunk->allocated = true;
  245. chunk->length = size;
  246. *res = offset + sizeof(struct chunk);
  247. return 0;
  248. }
  249. else
  250. {
  251. // too big, split
  252. uint32_t next = chunk->offset_next;
  253. uint32_t prev = offset;
  254. uint32_t next_offset = offset + sizeof(struct chunk) + alloc_size;
  255. chunk->offset_next = next_offset;
  256. chunk->length = size;
  257. chunk->allocated = true;
  258. chunk = data + next_offset;
  259. chunk->offset_prev = prev;
  260. chunk->offset_next = next;
  261. chunk->length = next - next_offset - sizeof(struct chunk);
  262. chunk->allocated = false;
  263. if (next)
  264. {
  265. struct chunk *chunk = data + next;
  266. chunk->offset_prev = next_offset;
  267. }
  268. *res = offset + sizeof(struct chunk);
  269. return 0;
  270. }
  271. }
  272. offset_prev = offset;
  273. offset = chunk->offset_next;
  274. }
  275. }
  276. uint32_t account_data_len(void *data, uint32_t offset)
  277. {
  278. // Nothing to do
  279. if (!offset)
  280. return 0;
  281. offset -= sizeof(struct chunk);
  282. struct chunk *chunk = data + offset;
  283. return chunk->length;
  284. }
  285. void account_data_free(void *data, uint32_t offset)
  286. {
  287. // Nothing to do
  288. if (!offset)
  289. return;
  290. offset -= sizeof(struct chunk);
  291. struct chunk *chunk = data + offset;
  292. chunk->allocated = false;
  293. // merge with previous chunk?
  294. if (chunk->offset_prev)
  295. {
  296. struct chunk *prev = data + chunk->offset_prev;
  297. if (!prev->allocated)
  298. {
  299. // merge
  300. offset = chunk->offset_prev;
  301. if (chunk->offset_next)
  302. {
  303. prev->length = chunk->offset_next - offset - sizeof(struct chunk);
  304. prev->offset_next = chunk->offset_next;
  305. struct chunk *next = data + chunk->offset_next;
  306. next->offset_prev = offset;
  307. }
  308. else
  309. {
  310. prev->offset_next = 0;
  311. prev->length = 0;
  312. }
  313. chunk = prev;
  314. }
  315. }
  316. // merge with next chunk?
  317. if (chunk->offset_next)
  318. {
  319. struct chunk *next = data + chunk->offset_next;
  320. if (!next->allocated)
  321. {
  322. // merge
  323. if (next->offset_next)
  324. {
  325. chunk->offset_next = next->offset_next;
  326. chunk->length = chunk->offset_next - offset - sizeof(struct chunk);
  327. struct chunk *next = data + chunk->offset_next;
  328. next->offset_prev = offset;
  329. }
  330. else
  331. {
  332. chunk->offset_next = 0;
  333. chunk->length = 0;
  334. }
  335. }
  336. }
  337. }
  338. uint64_t account_data_realloc(SolAccountInfo *ai, uint32_t offset, uint32_t size, uint32_t *res)
  339. {
  340. if (!size)
  341. {
  342. account_data_free(ai, offset);
  343. return 0;
  344. }
  345. if (!offset)
  346. {
  347. return account_data_alloc(ai, size, res);
  348. }
  349. void *data = ai->data;
  350. uint32_t chunk_offset = offset - sizeof(struct chunk);
  351. struct chunk *chunk = data + chunk_offset;
  352. struct chunk *next = data + chunk->offset_next;
  353. uint32_t existing_size = chunk->offset_next - offset;
  354. uint32_t alloc_size = ROUND_UP(size, 8);
  355. // 1. Is the existing chunk big enough
  356. if (size <= existing_size)
  357. {
  358. chunk->length = size;
  359. // can we free up some space
  360. if (existing_size >= alloc_size + sizeof(struct chunk) + 8)
  361. {
  362. uint32_t new_next_offset = offset + alloc_size;
  363. if (!next->allocated)
  364. {
  365. // merge with next chunk
  366. if (!next->offset_next)
  367. {
  368. // the trailing free chunk
  369. chunk->offset_next = new_next_offset;
  370. next = data + new_next_offset;
  371. next->offset_prev = chunk_offset;
  372. next->offset_next = 0;
  373. next->allocated = false;
  374. next->length = 0;
  375. }
  376. else
  377. {
  378. // merge with next chunk
  379. chunk->offset_next = new_next_offset;
  380. uint32_t offset_next_next = next->offset_next;
  381. next = data + new_next_offset;
  382. next->offset_prev = chunk_offset;
  383. next->offset_next = offset_next_next;
  384. next->allocated = false;
  385. next->length = offset_next_next - new_next_offset - sizeof(struct chunk);
  386. next = data + offset_next_next;
  387. next->offset_prev = new_next_offset;
  388. }
  389. }
  390. else
  391. {
  392. // insert a new chunk
  393. uint32_t offset_next_next = chunk->offset_next;
  394. chunk->offset_next = new_next_offset;
  395. next = data + new_next_offset;
  396. next->offset_prev = chunk_offset;
  397. next->offset_next = offset_next_next;
  398. next->allocated = false;
  399. next->length = offset_next_next - new_next_offset - sizeof(struct chunk);
  400. next = data + offset_next_next;
  401. next->offset_prev = new_next_offset;
  402. }
  403. }
  404. *res = offset;
  405. return 0;
  406. }
  407. // 2. Can we use the next chunk to expand our chunk to fit
  408. // Note because we always merge neighbours, free chunks do not have free
  409. // neighbours.
  410. if (!next->allocated)
  411. {
  412. if (next->offset_next)
  413. {
  414. uint32_t merged_size = next->offset_next - offset;
  415. if (size < merged_size)
  416. {
  417. if (merged_size - alloc_size < 8 + sizeof(struct chunk))
  418. {
  419. // merge the two chunks
  420. chunk->offset_next = next->offset_next;
  421. chunk->length = size;
  422. next = data + chunk->offset_next;
  423. next->offset_prev = chunk_offset;
  424. }
  425. else
  426. {
  427. // expand our chunk to fit and shrink the next chunk
  428. uint32_t offset_next = offset + alloc_size;
  429. uint32_t offset_next_next = next->offset_next;
  430. chunk->offset_next = offset_next;
  431. chunk->length = size;
  432. next = data + offset_next;
  433. next->offset_prev = chunk_offset;
  434. next->offset_next = offset_next_next;
  435. next->length = offset_next_next - offset_next - sizeof(struct chunk);
  436. next->allocated = false;
  437. next = data + offset_next_next;
  438. next->offset_prev = offset_next;
  439. }
  440. *res = offset;
  441. return 0;
  442. }
  443. }
  444. else
  445. {
  446. if (offset + alloc_size + sizeof(struct chunk) < ai->data_len)
  447. {
  448. chunk->offset_next = offset + alloc_size;
  449. chunk->length = size;
  450. next = data + chunk->offset_next;
  451. next->offset_prev = chunk_offset;
  452. next->offset_next = 0;
  453. next->allocated = false;
  454. next->length = 0;
  455. *res = offset;
  456. return 0;
  457. }
  458. }
  459. }
  460. uint32_t old_length = account_data_len(data, offset);
  461. uint32_t new_offset;
  462. uint64_t rc = account_data_alloc(ai, size, &new_offset);
  463. if (rc)
  464. return rc;
  465. __memcpy(data + new_offset, data + offset, old_length);
  466. account_data_free(ai, offset);
  467. *res = new_offset;
  468. return 0;
  469. }
  470. #ifdef TEST
  471. // To run the test:
  472. // clang -DTEST -DSOL_TEST -O3 -Wall solana.c stdlib.c -o test && ./test
  473. #include <assert.h>
  474. void validate_heap(void *data, uint32_t offs[100], uint32_t lens[100])
  475. {
  476. uint32_t offset = ((uint32_t *)data)[1];
  477. uint32_t last_offset = 0;
  478. for (;;)
  479. {
  480. struct chunk *chk = data + offset;
  481. //printf("chunk: offset:%x prev:%x next:%x length:%x allocated:%d\n", offset, chk->offset_prev, chk->offset_next, chk->length, chk->allocated);
  482. if (chk->length == 0 || chk->offset_next == 0)
  483. {
  484. assert(chk->length == 0 && chk->offset_next == 0 && chk->offset_prev == last_offset);
  485. //printf("last object at 0x%08x\n", offset);
  486. return;
  487. }
  488. assert(chk->offset_prev == last_offset && chk->length != 0);
  489. //printf("found object length %x at 0x%08lx allocated %d\n", chk->length, offset + sizeof(struct chunk), chk->allocated);
  490. assert(chk->offset_next - offset - sizeof(struct chunk) >= chk->length);
  491. if (chk->allocated)
  492. {
  493. bool found = false;
  494. uint32_t off = offset + sizeof(struct chunk);
  495. for (int i = 0; i < 100; i++)
  496. {
  497. if (offs[i] == off)
  498. {
  499. assert(!found);
  500. found = true;
  501. uint8_t *mem = data + off;
  502. for (int x = 0; x < lens[i]; x++)
  503. {
  504. assert(mem[x] == i);
  505. }
  506. }
  507. }
  508. assert(found);
  509. }
  510. else
  511. {
  512. // make sure we do not have this in our allocated list
  513. uint32_t off = offset + sizeof(struct chunk);
  514. for (int i = 0; i < 100; i++)
  515. {
  516. assert(offs[i] != off);
  517. }
  518. }
  519. last_offset = offset;
  520. offset = chk->offset_next;
  521. }
  522. }
  523. int main()
  524. {
  525. uint8_t data[0x10000];
  526. SolAccountInfo ai;
  527. ai.data = data;
  528. ai.data_len = sizeof(data);
  529. uint32_t offs[100], lens[100];
  530. uint32_t allocs = 0;
  531. memset(data, 0, sizeof(data));
  532. ((uint32_t *)data)[0] = 0x41424344;
  533. ((uint32_t *)data)[1] = 0x20;
  534. memset(offs, 0, sizeof(offs));
  535. int seed = time(NULL);
  536. printf("seed: %d\n", seed);
  537. srand(seed);
  538. for (;;)
  539. {
  540. validate_heap(data, offs, lens);
  541. int n = rand() % 100;
  542. if (offs[n] == 0)
  543. {
  544. //printf("STEP: alloc %d\n", n);
  545. offs[n] = account_data_alloc(&ai, 100);
  546. memset(data + offs[n], n, 100);
  547. lens[n] = 100;
  548. }
  549. else if (rand() % 2)
  550. {
  551. //printf("STEP: free %d (0x%x)\n", n, offs[n]);
  552. account_data_free(&ai, offs[n]);
  553. offs[n] = 0;
  554. }
  555. else
  556. {
  557. int size = (rand() % 200) + 10;
  558. int old_size = account_data_len(&ai, offs[n]);
  559. offs[n] = account_data_realloc(&ai, offs[n], size);
  560. if (size > old_size)
  561. memset(data + offs[n] + old_size, n, size - old_size);
  562. lens[n] = size;
  563. }
  564. }
  565. }
  566. void sol_panic_(const char *s, uint64_t len, uint64_t line, uint64_t column)
  567. {
  568. printf("panic: %s line %lld", s, line);
  569. }
  570. void *sol_alloc_free_(uint64_t size, void *ptr)
  571. {
  572. if (size)
  573. {
  574. return realloc(ptr, size);
  575. }
  576. else
  577. {
  578. free(ptr);
  579. return NULL;
  580. }
  581. }
  582. int solang_dispatch(const uint8_t *input, uint64_t input_len, SolAccountInfo *ka) {}
  583. #endif