rgb-cln/daemon/onion.c

105 lines
2.5 KiB
C

#include "log.h"
#include "onion.h"
#include "peer.h"
#include "protobuf_convert.h"
#include "routing.h"
#include <string.h>
/* FIXME: http://www.cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf */
/* Frees r */
static const u8 *to_onion(const tal_t *ctx, const Route *r)
{
u8 *onion = tal_arr(ctx, u8, route__get_packed_size(r));
route__pack(r, onion);
tal_free(r);
return onion;
}
/* Create an onion for sending msatoshi_with_fees down path. */
const u8 *onion_create(const tal_t *ctx,
secp256k1_context *secpctx,
struct node_connection **path,
u64 msatoshi, s64 fees)
{
Route *r = tal(ctx, Route);
int i;
u64 amount = msatoshi;
route__init(r);
r->n_steps = tal_count(path) + 1;
r->steps = tal_arr(r, RouteStep *, r->n_steps);
/* Create backwards, so we can get fees correct. */
for (i = tal_count(path) - 1; i >= 0; i--) {
r->steps[i] = tal(r, RouteStep);
route_step__init(r->steps[i]);
r->steps[i]->next_case = ROUTE_STEP__NEXT_BITCOIN;
r->steps[i]->bitcoin = pubkey_to_proto(r, secpctx,
&path[i]->dst->id);
r->steps[i]->amount = amount;
amount += connection_fee(path[i], amount);
}
/* Now the stop marker. */
i = tal_count(path);
r->steps[i] = tal(r, RouteStep);
route_step__init(r->steps[i]);
r->steps[i]->next_case = ROUTE_STEP__NEXT_END;
r->steps[i]->end = true;
r->steps[i]->amount = 0;
assert(amount == msatoshi + fees);
return to_onion(ctx, r);
}
static void *proto_tal_alloc(void *allocator_data, size_t size)
{
return tal_arr(allocator_data, char, size);
}
static void proto_tal_free(void *allocator_data, void *pointer)
{
tal_free(pointer);
}
/* Decode next step in the route, and fill out the onion to send onwards. */
RouteStep *onion_unwrap(struct peer *peer,
const void *data, size_t len, const u8 **next)
{
struct ProtobufCAllocator prototal;
Route *r;
RouteStep *step;
/* De-protobuf it. */
prototal.alloc = proto_tal_alloc;
prototal.free = proto_tal_free;
prototal.allocator_data = tal(peer, char);
r = route__unpack(&prototal, len, data);
if (!r || r->n_steps == 0) {
log_unusual(peer->log, "Failed to unwrap onion");
tal_free(prototal.allocator_data);
return NULL;
}
/* Remove first step. */
step = r->steps[0];
/* Make sure that step owns the rest */
tal_steal(peer, step);
tal_steal(step, prototal.allocator_data);
/* Re-pack with remaining steps. */
r->n_steps--;
memmove(r->steps, r->steps + 1, sizeof(*r->steps) * r->n_steps);
if (!r->n_steps) {
*next = NULL;
tal_free(r);
} else
*next = to_onion(peer, r);
return step;
}