basic parsing

This commit is contained in:
Michele Balistreri 2024-07-04 15:26:54 +02:00
parent 05d7a0143f
commit bcc9ce484c
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
1 changed files with 112 additions and 4 deletions

View File

@ -1,16 +1,124 @@
#include "core.h" #include "core.h"
#include "mem.h"
#include "bitcoin/psbt.h" #include "bitcoin/psbt.h"
void core_btc_tx_elem_handler(psbt_elem_t* rec) { #define BTC_MAX_INPUTS 10
#define BTC_MAX_OUTPUTS 10
enum btc_input_type {
BTC_INPUT_TYPE_LEGACY,
BTC_INPUT_TYPE_SEGWIT
};
enum btc_sighash_flag {
SIGHASH_DEFAULT = 0x00,
SIGHASH_ALL = 0x01,
SIGHASH_NONE = 0x02,
SIGHASH_SINGLE = 0x03,
};
typedef struct {
uint8_t* pubkey_hash;
uint8_t* amount;
uint8_t* bip32_path;
uint32_t bip32_path_len;
uint32_t master_fingerprint;
uint32_t sighash_flag;
enum btc_input_type input_type;
} psbt_input_data_t;
struct btc_tx_ctx {
psbt_tx_t tx;
psbt_txin_t inputs[BTC_MAX_INPUTS];
psbt_txout_t outputs[BTC_MAX_OUTPUTS];
psbt_input_data_t input_data[BTC_MAX_INPUTS];
size_t input_count;
size_t output_count;
app_err_t error;
};
static void core_btc_psbt_rec_handler(struct btc_tx_ctx* tx_data, size_t index, psbt_record_t* rec) {
if (rec->scope != PSBT_SCOPE_INPUTS) {
return;
} else if (index >= tx_data->input_count) {
tx_data->error = ERR_DATA;
return;
}
switch (rec->type) {
case PSBT_IN_NON_WITNESS_UTXO:
case PSBT_IN_REDEEM_SCRIPT:
case PSBT_IN_WITNESS_SCRIPT:
//TODO: implement
tx_data->error = ERR_DECODE;
break;
case PSBT_IN_WITNESS_UTXO:
if ((rec->val[8] != 22) || (rec->val[9] != 0x00) || (rec->val[10] != 20)) {
tx_data->error = ERR_DECODE;
return;
}
tx_data->input_data[index].input_type = BTC_INPUT_TYPE_SEGWIT;
tx_data->input_data[index].amount = rec->val;
tx_data->input_data[index].pubkey_hash = &rec->val[11];
break;
case PSBT_IN_BIP32_DERIVATION:
memcpy(&tx_data->input_data[index].master_fingerprint, rec->val, sizeof(uint32_t));
tx_data->input_data[index].bip32_path = &rec->val[4];
tx_data->input_data[index].bip32_path_len = rec->val_size - 4;
break;
case PSBT_IN_SIGHASH_TYPE:
memcpy(&tx_data->input_data[index].sighash_flag, rec->val, sizeof(uint32_t));
break;
}
}
static void core_btc_txelem_handler(struct btc_tx_ctx* tx_data, psbt_txelem_t* elem) {
switch (elem->elem_type) {
case PSBT_TXELEM_TX:
memcpy(&tx_data->tx, elem->elem.tx, sizeof(psbt_tx_t));
break;
case PSBT_TXELEM_TXIN:
if (tx_data->input_count < BTC_MAX_INPUTS) {
memcpy(&tx_data->inputs[tx_data->input_count++], elem->elem.txin, sizeof(psbt_txin_t));
} else {
tx_data->error = ERR_FULL;
}
break;
case PSBT_TXELEM_TXOUT:
if (tx_data->output_count < BTC_MAX_OUTPUTS) {
memcpy(&tx_data->outputs[tx_data->output_count++], elem->elem.txout, sizeof(psbt_txout_t));
} else {
tx_data->error = ERR_FULL;
}
break;
default:
break;
}
}
static void core_btc_parser_cb(psbt_elem_t* rec) {
struct btc_tx_ctx* tx_data = (struct btc_tx_ctx*) rec->user_data;
if (rec->type == PSBT_ELEM_RECORD) { if (rec->type == PSBT_ELEM_RECORD) {
core_btc_psbt_rec_handler(tx_data, rec->index, rec->elem.rec);
} else if (rec->type == PSBT_ELEM_TXELEM) { } else if (rec->type == PSBT_ELEM_TXELEM) {
core_btc_txelem_handler(tx_data, rec->elem.txelem);
} }
} }
void core_btc_psbt_run(struct zcbor_string* qr_request) { void core_btc_psbt_run(struct zcbor_string* qr_request) {
struct btc_tx_ctx* tx_ctx = (struct btc_tx_ctx*) &qr_request->value[(qr_request->len + 3) & ~0x3];
memset(tx_ctx, 0, sizeof(struct btc_tx_ctx));
psbt_t psbt; psbt_t psbt;
psbt_init(&psbt, (uint8_t*) qr_request->value, qr_request->len); psbt_init(&psbt, (uint8_t*) qr_request->value, qr_request->len);
psbt_read(qr_request->value, qr_request->len, &psbt, core_btc_tx_elem_handler, NULL); psbt_read(qr_request->value, qr_request->len, &psbt, core_btc_parser_cb, tx_ctx);
if (!tx_ctx->error != ERR_OK) {
//TODO: add error message
return;
}
} }