diff --git a/blkmaker.c b/blkmaker.c index f7d325c..e1acd6d 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -22,6 +22,15 @@ const char *blkmk_supported_rules[] = { NULL }; +bool blkmk_supports_rule(const char * const rulename) { + for (const char **r = blkmk_supported_rules; *r; ++r) { + if (!strcmp(rulename, *r)) { + return true; + } + } + return false; +} + static inline void my_htole32(unsigned char *buf, uint32_t n) { buf[0] = (n >> 0) % 256; diff --git a/blkmaker.h b/blkmaker.h index 4c2a7d6..809ec6b 100644 --- a/blkmaker.h +++ b/blkmaker.h @@ -8,7 +8,8 @@ #include #define BLKMAKER_VERSION (5L) -#define BLKMAKER_MAX_BLOCK_VERSION (4) +#define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff) +#define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4) extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz); diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index ecbc52d..cbce12f 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -251,10 +251,68 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t } } - if (tmpl->version > BLKMAKER_MAX_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height)) + if ((tmpl->version & 0xe0000000) == 0x20000000 && (v = json_object_get(json, "vbavailable")) && json_is_object(v) && (v = json_object_get(json, "rules")) && json_is_array(v)) { + // calloc so that a failure doesn't result in freeing a random pointer + size_t n = json_array_size(v); + tmpl->rules = calloc(n + 1, sizeof(*tmpl->rules)); + for (size_t i = 0; i < n; ++i) { + v2 = json_array_get(v, i); + if (!json_is_string(v2)) { + return "Non-String data in template rules list"; + } + s = json_string_value(v2); + if (s[0] == '!') { + ++s; + if (!blkmk_supports_rule(s)) { + return "Unsupported rule strictly required by template"; + } + } else { + if (!blkmk_supports_rule(s)) { + tmpl->unsupported_rule = true; + } + } + tmpl->rules[i] = strdup(s); + if (!tmpl->rules[i]) { + return "Memory allocation error parsing rules"; + } + } + + v = json_object_get(json, "vbavailable"); + n = json_object_size(v); + tmpl->vbavailable = calloc(n + 1, sizeof(*tmpl->vbavailable)); + struct blktmpl_vbassoc **cur_vbassoc = tmpl->vbavailable; + for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++cur_vbassoc) { + v2 = json_object_iter_value(iter); + if (!json_is_number(v2)) { + return "Invalid type for vbavailable bit"; + } + double bitnum = json_number_value(v2); + if (bitnum < 0 || bitnum > 28 || (unsigned)bitnum != bitnum) { + return "Invalid bit number in vbavailable"; + } + *cur_vbassoc = malloc(sizeof(**cur_vbassoc)); + if (!*cur_vbassoc) { + return "Memory allocation error for struct blktmpl_vbassoc"; + } + **cur_vbassoc = (struct blktmpl_vbassoc){ + .name = strdup(json_object_iter_key(iter)), + .bitnum = bitnum, + }; + if (!(*cur_vbassoc)->name) { + return "Memory allocation error for vbavailable name"; + } + } + + v = json_object_get(json, "vbrequired"); + if (v && json_is_number(v)) { + tmpl->vbrequired = json_number_value(v); + } + } + else + if (tmpl->version > BLKMAKER_MAX_PRERULES_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height)) { if (tmpl->mutations & BMM_VERDROP) - tmpl->version = tmpl->height ? BLKMAKER_MAX_BLOCK_VERSION : 1; + tmpl->version = tmpl->height ? BLKMAKER_MAX_PRERULES_BLOCK_VERSION : 1; else if (!(tmpl->mutations & BMM_VERFORCE)) return "Unrecognized block version, and not allowed to reduce or force it"; diff --git a/blktemplate.c b/blktemplate.c index f70f30f..fd990b7 100644 --- a/blktemplate.c +++ b/blktemplate.c @@ -117,5 +117,20 @@ void blktmpl_free(blktemplate_t *tmpl) { free(tmpl->workid); free(tmpl->lp.id); free(tmpl->lp.uri); + + if (tmpl->rules) { + for (char **currule = tmpl->rules; *currule; ++currule) { + free(*currule); + } + free(tmpl->rules); + } + if (tmpl->vbavailable) { + for (struct blktmpl_vbassoc **curvb = tmpl->vbavailable; *curvb; ++curvb) { + free((*curvb)->name); + free(*curvb); + } + free(tmpl->vbavailable); + } + free(tmpl); } diff --git a/blktemplate.h b/blktemplate.h index 263976a..83b92ee 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -78,6 +78,11 @@ extern gbt_capabilities_t blktmpl_getcapability(const char *); typedef gbt_capabilities_t blkmutations_t; +struct blktmpl_vbassoc { + char *name; + uint8_t bitnum; +}; + // WARNING: Do not allocate this (ABI is not guaranteed to remain fixed-size) typedef struct { uint32_t version; @@ -123,6 +128,11 @@ typedef struct { int _mrklbranchcount; libblkmaker_hash_t _mrklroot; unsigned int next_dataid; + + char **rules; + bool unsupported_rule; + struct blktmpl_vbassoc **vbavailable; + uint32_t vbrequired; } blktemplate_t; extern blktemplate_t *blktmpl_create(); diff --git a/private.h b/private.h index 14eacf1..055061b 100644 --- a/private.h +++ b/private.h @@ -7,6 +7,7 @@ // blkmaker.c extern const char *blkmk_supported_rules[]; extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz); +extern bool blkmk_supports_rule(const char *rulename); // blktemplate.c extern void _blktxn_free(struct blktxn_t *);