Skip to content

Commit

Permalink
Generalized and strenghtened relative pointers; refactored policy_nod…
Browse files Browse the repository at this point in the history
…e_scriptlist_t to use relative pointers
  • Loading branch information
bigspider committed Jan 10, 2024
1 parent cf28de7 commit c7a2b86
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 57 deletions.
37 changes: 20 additions & 17 deletions src/common/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1278,15 +1278,16 @@ static int parse_script(buffer_t *in_buf,
}

node->n = 0;
node->scriptlist =
(policy_node_scriptlist_t *) buffer_alloc(out_buf,
sizeof(policy_node_scriptlist_t),
true);
if (node->scriptlist == NULL) {
policy_node_scriptlist_t *scriptlist =
buffer_alloc(out_buf, sizeof(policy_node_scriptlist_t), true);
if (scriptlist == NULL) {
return WITH_ERROR(-1, "Out of memory");
}
policy_node_scriptlist_t *cur = node->scriptlist;
cur->next = NULL;
i_policy_node_scriptlist(&node->scriptlist, scriptlist);

policy_node_scriptlist_t *cur = scriptlist;

i_policy_node_scriptlist(&cur->next, NULL);

int count_z = 0;
int count_o = 0;
Expand Down Expand Up @@ -1333,16 +1334,18 @@ static int parse_script(buffer_t *in_buf,

// peek, if next character is ',', consume it and exit
if (consume_character(in_buf, ',')) {
cur->next =
policy_node_scriptlist_t *next =
(policy_node_scriptlist_t *) buffer_alloc(out_buf,
sizeof(policy_node_scriptlist_t),
true);
if (cur->next == NULL) {
if (next == NULL) {
return WITH_ERROR(-1, "Out of memory");
}

cur = cur->next;
cur->next = NULL;
i_policy_node_scriptlist(&cur->next, next);

cur = next;
i_policy_node_scriptlist(&cur->next, NULL);
} else {
// no more scripts to parse
break;
Expand Down Expand Up @@ -1979,7 +1982,7 @@ static int compute_thresh_ops(const policy_node_thresh_t *node,

if (node->n > MAX_N_IN_THRESH) return -1;

policy_node_scriptlist_t *cur = node->scriptlist;
policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);

out->count = 0;

Expand All @@ -2002,7 +2005,7 @@ static int compute_thresh_ops(const policy_node_thresh_t *node,
++sats_size;
memmove(sats, next_sats, sats_size * sizeof(sats[0]));

cur = cur->next;
cur = r_policy_node_scriptlist(&cur->next);
}

out->sat = sats[node->k];
Expand All @@ -2027,7 +2030,7 @@ static int compute_thresh_stacksize(const policy_node_thresh_t *node,

if (node->n > MAX_N_IN_THRESH) return -1;

policy_node_scriptlist_t *cur = node->scriptlist;
policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);

sats[0] = 0;
int sats_size = 1;
Expand All @@ -2045,7 +2048,7 @@ static int compute_thresh_stacksize(const policy_node_thresh_t *node,
++sats_size;
memmove(sats, next_sats, sats_size * sizeof(sats[0]));

cur = cur->next;
cur = r_policy_node_scriptlist(&cur->next);
}

out->sat = sats[node->k];
Expand Down Expand Up @@ -2503,7 +2506,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
case TOKEN_THRESH: {
const policy_node_thresh_t *node = (const policy_node_thresh_t *) policy_node;

policy_node_scriptlist_t *cur = node->scriptlist;
policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);

int count_s = 0;
int count_e = 0;
Expand All @@ -2526,7 +2529,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
if (t.m) {
++count_m;
}
cur = cur->next;
cur = r_policy_node_scriptlist(&cur->next);

out->g |= t.g;
out->h |= t.h;
Expand Down
96 changes: 60 additions & 36 deletions src/common/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <stdint.h>
#include <assert.h>

#include "ledger_assert.h"

#include "common/bip32.h"
#include "common/buffer.h"
#include "../constants.h"
Expand Down Expand Up @@ -190,37 +192,57 @@ static inline void init_relative_ptr(ptr_rel_t *relative_ptr, void *node) {

// Defines a relative pointer type for name##t, and the conversion functions to/from a relative
// pointer and a pointer to name##_t.
// Relative pointers use an uint16_t to represent the offset; therefore, the offset must be at most.
// 65536. Bounds are not checked, therefore it needs to be handled with care.
#define DEFINE_REL_PTR(name, type) \
/* \
* Relative pointer structure for `type`. \
* \
* This structure holds an offset that is used to calculate the actual pointer \
* to a `type` object. \
*/ \
typedef struct rptr_##name##_s { \
uint16_t offset; \
} rptr_##name##_t; \
\
/* \
* Resolve a relative pointer to a `type` object. \
* \
* @param ptr A pointer to the relative pointer structure. \
* @return A constant pointer to the `type` object. \
*/ \
static inline const type *r_##name(const rptr_##name##_t *ptr) { \
return (const type *) ((const uint8_t *) ptr + ptr->offset); \
} \
\
/* \
* Initialize a relative pointer to a `type` object. \
* \
* @param relative_ptr A pointer to the relative pointer structure to be initialized. \
* @param node A pointer to the `type` object. \
*/ \
static inline void i_##name(rptr_##name##_t *relative_ptr, void *node) { \
relative_ptr->offset = (uint16_t) ((uint8_t *) node - (uint8_t *) relative_ptr); \
// Relative pointers use an uint16_t to represent the offset; therefore, the offset must be
// non-negative and at most 65535.
// An offset of 0 corresponds to a NULL pointer in the conversion (and vice-versa).
#define DEFINE_REL_PTR(name, type) \
/* \
* Relative pointer structure for `type`. \
* \
* This structure holds an offset that is used to calculate the actual pointer \
* to a `type` object. \
*/ \
typedef struct rptr_##name##_s { \
uint16_t offset; \
} rptr_##name##_t; \
\
/* \
* Resolve a relative pointer to a `type` object. \
* \
* @param ptr A pointer to the relative pointer structure. \
* @return A pointer to the `type` object. \
*/ \
static inline type *r_##name(const rptr_##name##_t *ptr) { \
if (ptr->offset == 0) \
return NULL; \
else \
return (type *) ((const uint8_t *) ptr + ptr->offset); \
} \
\
/* \
* Returns true when the offset of the relative pointer is 0 (equivalent to a NULL pointer). \
* \
* @param relative_ptr A relative pointer. \
*/ \
static inline bool isnull_##name(const rptr_##name##_t *ptr) { \
return ptr->offset == 0; \
} \
\
/* \
* Initialize a relative pointer to a `type` object. \
* \
* @param relative_ptr A pointer to the relative pointer structure to be initialized. \
* @param obj A pointer to the `type` object. \
*/ \
static inline void i_##name(rptr_##name##_t *relative_ptr, void *obj) { \
if (obj == NULL) \
relative_ptr->offset = 0; \
else { \
int offset = (uint8_t *) obj - (uint8_t *) relative_ptr; \
LEDGER_ASSERT(offset >= 0 && offset < UINT16_MAX, \
"Relative pointer's offset must be between 0 and 65535"); \
relative_ptr->offset = (uint16_t) offset; \
} \
}

// 2 bytes
Expand Down Expand Up @@ -346,9 +368,12 @@ typedef struct {
} policy_node_multisig_t;

// 8 bytes
struct policy_node_scriptlist_s; // forward declaration, as the struct is recursive

DEFINE_REL_PTR(policy_node_scriptlist, struct policy_node_scriptlist_s)

typedef struct policy_node_scriptlist_s {
// TODO: change to relative pointers
struct policy_node_scriptlist_s *next;
rptr_policy_node_scriptlist_t next;
rptr_policy_node_t script;
} policy_node_scriptlist_t;

Expand All @@ -357,9 +382,8 @@ typedef struct {
struct policy_node_s base; // type is TOKEN_THRESH
int16_t k; // threshold
int16_t n; // number of child scripts
// TODO: change to relative pointers
policy_node_scriptlist_t
*scriptlist; // pointer to array of exactly n pointers to child scripts
rptr_policy_node_scriptlist_t
scriptlist; // pointer to array of exactly n pointers to child scripts
} policy_node_thresh_t;

typedef struct {
Expand Down
13 changes: 9 additions & 4 deletions src/handler/lib/policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "debug-helpers/debug.h"

#include "ledger_assert.h"

#define MAX_POLICY_DEPTH 10

// The last opcode must be processed as a VERIFY flag
Expand Down Expand Up @@ -752,9 +754,9 @@ __attribute__((warn_unused_result)) static int process_thresh_node(policy_parser

if (node->step < policy->n) {
// find the current child node
policy_node_scriptlist_t *cur = policy->scriptlist;
policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&policy->scriptlist);
for (size_t i = 0; i < node->step; i++) {
cur = cur->next;
cur = r_policy_node_scriptlist(&cur->next);
}

// process child node
Expand Down Expand Up @@ -1678,8 +1680,11 @@ int get_key_placeholder_by_index(const policy_node_t *policy,
const policy_node_thresh_t *node = (const policy_node_thresh_t *) policy;
bool found;
int ret = 0;
policy_node_scriptlist_t *cur_child = node->scriptlist;
policy_node_scriptlist_t *cur_child = r_policy_node_scriptlist(&node->scriptlist);
for (int script_idx = 0; script_idx < node->n; script_idx++) {
LEDGER_ASSERT(cur_child != NULL,
"The script should always have exactly n child scripts");

found = i < (unsigned int) ret;
int ret_partial = get_key_placeholder_by_index(r_policy_node(&cur_child->script),
found ? 0 : i - ret,
Expand All @@ -1688,7 +1693,7 @@ int get_key_placeholder_by_index(const policy_node_t *policy,
if (ret_partial < 0) return -1;

ret += ret_partial;
cur_child = cur_child->next;
cur_child = r_policy_node_scriptlist(&cur_child->next);
}
return ret;
}
Expand Down

0 comments on commit c7a2b86

Please sign in to comment.