funding: remove protobufs.

Use our own structure with the information we need about HTLCs,
and remove protobufs from the API.

The is_funder() helper goes inside gather_updates.h.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-01-22 06:41:47 +10:30
parent d95d8a99c2
commit 6d6abd57e7
13 changed files with 188 additions and 106 deletions

View File

@ -7,10 +7,10 @@
#include "funding.h"
#include "overflows.h"
#include "permute_tx.h"
#include "protobuf_convert.h"
#include <assert.h>
static bool add_htlc(struct bitcoin_tx *tx, size_t n,
const UpdateAddHtlc *h,
const struct channel_htlc *h,
const struct pubkey *ourkey,
const struct pubkey *theirkey,
const struct sha256 *rhash,
@ -23,22 +23,14 @@ static bool add_htlc(struct bitcoin_tx *tx, size_t n,
const struct sha256 *,
const struct sha256 *))
{
struct abs_locktime htlc_abstime;
struct sha256 htlc_rhash;
assert(!tx->output[n].script);
/* This shouldn't happen... */
if (!proto_to_abs_locktime(h->expiry, &htlc_abstime))
return false;
proto_to_sha256(h->r_hash, &htlc_rhash);
tx->output[n].script = scriptpubkey_p2sh(tx,
scriptpubkeyfn(tx, ourkey, theirkey,
&htlc_abstime, locktime, rhash,
&htlc_rhash));
&h->expiry, locktime, rhash,
&h->rhash));
tx->output[n].script_length = tal_count(tx->output[n].script);
tx->output[n].amount = h->amount_msat / 1000;
tx->output[n].amount = h->msatoshis / 1000;
return true;
}
@ -88,7 +80,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
/* HTLCs we've sent. */
for (i = 0; i < tal_count(cstate->a.htlcs); i++) {
if (!add_htlc(tx, num, cstate->a.htlcs[i],
if (!add_htlc(tx, num, &cstate->a.htlcs[i],
our_final, their_final,
rhash, their_locktime, scriptpubkey_htlc_send))
return tal_free(tx);
@ -96,7 +88,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
}
/* HTLCs we've received. */
for (i = 0; i < tal_count(cstate->b.htlcs); i++) {
if (!add_htlc(tx, num, cstate->b.htlcs[i],
if (!add_htlc(tx, num, &cstate->b.htlcs[i],
our_final, their_final,
rhash, their_locktime, scriptpubkey_htlc_recv))
return tal_free(tx);

View File

@ -2,11 +2,6 @@
#include <assert.h>
#include <string.h>
static bool is_funder(const OpenChannel *o)
{
return o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR;
}
static bool subtract_fees(uint64_t *funder, uint64_t *non_funder,
uint64_t *funder_fee, uint64_t *non_funder_fee,
bool non_funder_paying, uint64_t fee)
@ -38,19 +33,18 @@ static bool subtract_fees(uint64_t *funder, uint64_t *non_funder,
}
/* Total, in millisatoshi. */
static uint32_t htlcs_total(UpdateAddHtlc *const *htlcs)
static uint64_t htlcs_total(const struct channel_htlc *htlcs)
{
size_t i, n = tal_count(htlcs);
uint32_t total = 0;
uint64_t total = 0;
for (i = 0; i < n; i++)
total += htlcs[i]->amount_msat;
total += htlcs[i].msatoshis;
return total;
}
bool funding_delta(const OpenChannel *oa,
const OpenChannel *ob,
const OpenAnchor *anchor,
bool funding_delta(bool a_is_funder,
uint64_t anchor_satoshis,
int64_t delta_a_msat,
int64_t htlc_msat,
struct channel_oneside *a_side,
@ -65,11 +59,7 @@ bool funding_delta(const OpenChannel *oa,
b = b_side->pay_msat + b_side->fee_msat;
fee = a_side->fee_msat + b_side->fee_msat;
assert(a + b + htlcs_total(a_side->htlcs) + htlcs_total(b_side->htlcs)
== anchor->amount * 1000);
/* Only one can be funder. */
if (is_funder(oa) == is_funder(ob))
return false;
== anchor_satoshis * 1000);
/* B gets whatever A gives. */
delta_b_msat = -delta_a_msat;
@ -87,7 +77,7 @@ bool funding_delta(const OpenChannel *oa,
b += delta_b_msat;
/* Take off fee from both parties if possible. */
if (is_funder(oa))
if (a_is_funder)
got_fees = subtract_fees(&a, &b, &a_fee, &b_fee,
delta_b_msat < 0, fee);
else
@ -106,42 +96,41 @@ bool funding_delta(const OpenChannel *oa,
}
struct channel_state *initial_funding(const tal_t *ctx,
const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
bool am_funder,
uint64_t anchor_satoshis,
uint64_t fee)
{
struct channel_state *state = talz(ctx, struct channel_state);
state->a.htlcs = tal_arr(state, UpdateAddHtlc *, 0);
state->b.htlcs = tal_arr(state, UpdateAddHtlc *, 0);
state->a.htlcs = tal_arr(state, struct channel_htlc, 0);
state->b.htlcs = tal_arr(state, struct channel_htlc, 0);
if (fee > anchor->amount)
if (fee > anchor_satoshis)
return tal_free(state);
if (anchor->amount > (1ULL << 32) / 1000)
if (anchor_satoshis > (1ULL << 32) / 1000)
return tal_free(state);
/* Initially, all goes back to funder. */
state->a.pay_msat = anchor->amount * 1000 - fee * 1000;
state->a.pay_msat = anchor_satoshis * 1000 - fee * 1000;
state->a.fee_msat = fee * 1000;
/* If B (not A) is funder, invert. */
if (is_funder(b))
if (!am_funder)
invert_cstate(state);
/* This checks we only have 1 anchor, and is nice code reuse. */
if (!funding_delta(a, b, anchor, 0, 0, &state->a, &state->b))
return tal_free(state);
/* Make sure it checks out. */
assert(funding_delta(am_funder, anchor_satoshis, 0, 0,
&state->a, &state->b));
return state;
}
/* We take the minimum. If one side offers too little, it should be rejected */
uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b)
uint64_t commit_fee(uint64_t a_satoshis, uint64_t b_satoshis)
{
if (a->commitment_fee < b->commitment_fee)
return a->commitment_fee;
return b->commitment_fee;
if (a_satoshis < b_satoshis)
return a_satoshis;
return b_satoshis;
}
void invert_cstate(struct channel_state *cstate)
@ -152,3 +141,27 @@ void invert_cstate(struct channel_state *cstate)
cstate->a = cstate->b;
cstate->b = tmp;
}
void funding_add_htlc(struct channel_oneside *creator,
u32 msatoshis, const struct abs_locktime *expiry,
const struct sha256 *rhash)
{
size_t n = tal_count(creator->htlcs);
tal_resize(&creator->htlcs, n+1);
creator->htlcs[n].msatoshis = msatoshis;
creator->htlcs[n].expiry = *expiry;
creator->htlcs[n].rhash = *rhash;
}
struct channel_state *copy_funding(const tal_t *ctx,
const struct channel_state *cstate)
{
struct channel_state *cs = tal_dup(ctx, struct channel_state, cstate);
cs->a.htlcs = tal_dup_arr(cs, struct channel_htlc, cs->a.htlcs,
tal_count(cs->a.htlcs), 0);
cs->b.htlcs = tal_dup_arr(cs, struct channel_htlc, cs->b.htlcs,
tal_count(cs->b.htlcs), 0);
return cs;
}

View File

@ -1,15 +1,22 @@
#ifndef LIGHTNING_FUNDING_H
#define LIGHTNING_FUNDING_H
#include "config.h"
#include "lightning.pb-c.h"
#include "bitcoin/locktime.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/tal/tal.h>
#include <stdbool.h>
struct channel_htlc {
u64 msatoshis;
struct abs_locktime expiry;
struct sha256 rhash;
};
struct channel_oneside {
/* Payment and fee is in millisatoshi. */
uint32_t pay_msat, fee_msat;
/* Use tal_count to get the number */
UpdateAddHtlc **htlcs;
struct channel_htlc *htlcs;
};
struct channel_state {
@ -19,43 +26,47 @@ struct channel_state {
/**
* initial_funding: Given A, B, and anchor, what is initial state?
* @ctx: tal context to allocate return value from.
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @am_funder: am I paying for the anchor?
* @anchor_satoshis: The anchor amount.
* @fee: amount to pay in fees (in satoshi).
*
* Returns state, or NULL if malformed.
*/
struct channel_state *initial_funding(const tal_t *ctx,
const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
bool am_funder,
uint64_t anchor_satoshis,
uint64_t fee);
/**
* copy_funding: Make a deep copy of channel_state
* @ctx: tal context to allocate return value from.
* @cstate: state to copy.
*/
struct channel_state *copy_funding(const tal_t *ctx,
const struct channel_state *cstate);
/**
* funding_delta: With this change, what's the new state?
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @a_is_funder: is A paying for the anchor?
* @anchor_satoshis: The anchor amount.
* @delta_a: How many millisatoshi A changes (-ve => A pay B, +ve => B pays A)
* @htlc: Millisatoshi A is putting into a HTLC (-ve if htlc is cancelled)
* @a_side: channel a's state to update.
* @b_side: channel b's state to update.
*/
bool funding_delta(const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
int64_t delta_a,
int64_t htlc,
bool funding_delta(bool a_is_funder,
uint64_t anchor_satoshis,
int64_t delta_a_msat,
int64_t htlc_msat,
struct channel_oneside *a_side,
struct channel_oneside *b_side);
/**
* commit_fee: Fee amount for commit tx.
* @a: A's openchannel offer
* @b: B's openchannel offer
* @a_satoshis: A's openchannel->commitment_fee offer
* @b_satoshis: B's openchannel->commitment_fee offer
*/
uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b);
uint64_t commit_fee(uint64_t a_satoshis, uint64_t b_satoshis);
/**
* invert_cstate: Get the other side's state.
@ -63,4 +74,15 @@ uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b);
*/
void invert_cstate(struct channel_state *cstate);
/**
* funding_add_htlc: append an HTLC to this side of the channel.
* @creator: channel_state->a or channel_state->b, whichever originated htlc
* @msatoshis: amount in millisatoshi
* @expiry: time it expires
* @rhash: hash of redeem secret
*/
void funding_add_htlc(struct channel_oneside *creator,
u32 msatoshis, const struct abs_locktime *expiry,
const struct sha256 *rhash);
#endif /* LIGHTNING_FUNDING_H */

View File

@ -15,6 +15,7 @@
#include "bitcoin/privkey.h"
#include "protobuf_convert.h"
#include "funding.h"
#include "gather_updates.h"
#include "version.h"
#include <unistd.h>
@ -70,9 +71,14 @@ int main(int argc, char *argv[])
if (!proto_to_pubkey(o2->commit_key, &pubkey2))
errx(1, "Invalid o2 commit_key");
cstate = initial_funding(ctx, o1, o2, a, commit_fee(o1, o2));
if (is_funder(o1) == is_funder(o2))
errx(1, "Must be exactly one funder");
cstate = initial_funding(ctx, is_funder(o1), a->amount,
commit_fee(o1->commitment_fee,
o2->commitment_fee));
if (!cstate)
errx(1, "Invalid open combination (need 1 anchor offer)");
errx(1, "Invalid open combination (need to cover fees)");
/* Now create our commitment tx. */
proto_to_sha256(o1->revocation_hash, &rhash);

View File

@ -85,7 +85,9 @@ int main(int argc, char *argv[])
errx(1, "Invalid o2 final pubkey");
/* We use this simply to get final revocation hash. */
gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 7,
gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee, o2->commitment_fee),
argv + 7,
NULL, &rhash, NULL, NULL);
/* Create redeem script */

View File

@ -67,7 +67,10 @@ int main(int argc, char *argv[])
sig2.stype = SIGHASH_ALL;
cstate = gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 5,
cstate = gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee,
o2->commitment_fee),
argv + 5,
NULL, &rhash, NULL, &sig2.sig);
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);

View File

@ -28,28 +28,32 @@ static size_t find_htlc(struct channel_oneside *oneside,
const Sha256Hash *rhash)
{
size_t i, n;
struct sha256 h;
proto_to_sha256(rhash, &h);
n = tal_count(oneside->htlcs);
for (i = 0; i < n; i++) {
if (oneside->htlcs[i]->r_hash->a == rhash->a
&& oneside->htlcs[i]->r_hash->b == rhash->b
&& oneside->htlcs[i]->r_hash->c == rhash->c
&& oneside->htlcs[i]->r_hash->d == rhash->d)
if (structeq(&oneside->htlcs[i].rhash, &h))
break;
}
return i;
}
static void add_htlc(struct channel_oneside *oneside, UpdateAddHtlc *ah,
static void add_htlc(struct channel_oneside *oneside,
const UpdateAddHtlc *ah,
const char *file)
{
size_t num = tal_count(oneside->htlcs);
struct sha256 rhash;
struct abs_locktime expiry;
if (find_htlc(oneside, ah->r_hash) != num)
errx(1, "Duplicate R hash in %s", file);
tal_resize(&oneside->htlcs, num+1);
oneside->htlcs[num] = ah;
proto_to_sha256(ah->r_hash, &rhash);
proto_to_abs_locktime(ah->expiry, &expiry);
funding_add_htlc(oneside, ah->amount_msat, &expiry, &rhash);
}
static void remove_htlc(struct channel_oneside *oneside, size_t n)
@ -85,13 +89,13 @@ static void update_rhash(const Sha256Hash *rhash,
(*num_updates)++;
}
static uint32_t htlcs_total(UpdateAddHtlc *const *htlcs)
static uint32_t htlcs_total(const struct channel_htlc *htlcs)
{
size_t i, n = tal_count(htlcs);
uint32_t total = 0;
for (i = 0; i < n; i++)
total += htlcs[i]->amount_msat;
total += htlcs[i].msatoshis;
return total;
}
@ -110,9 +114,12 @@ struct channel_state *gather_updates(const tal_t *ctx,
struct channel_state *cstate;
/* Start sanity check. */
cstate = initial_funding(NULL, o1, o2, oa, fee);
if (is_funder(o1) == is_funder(o2))
errx(1, "Must be exactly one funder");
cstate = initial_funding(NULL, is_funder(o1), oa->amount, fee);
if (!cstate)
errx(1, "Invalid open combination (need 1 anchor offer)");
errx(1, "Invalid open combination (need to cover fees)");
/* If they don't want these, use dummy ones. */
if (!our_rhash)
@ -156,14 +163,16 @@ struct channel_state *gather_updates(const tal_t *ctx,
case PKT__PKT_UPDATE_ADD_HTLC:
amount = pkt->update_add_htlc->amount_msat;
if (received) {
if (!funding_delta(o2, o1, oa, 0, amount,
if (!funding_delta(is_funder(o2), oa->amount,
0, amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
add_htlc(&cstate->b, pkt->update_add_htlc,
*argv);
} else {
if (!funding_delta(o1, o2, oa, 0, amount,
if (!funding_delta(is_funder(o1), oa->amount,
0, amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -183,8 +192,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_timedout_htlc->r_hash);
if (n == tal_count(cstate->b.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->b.htlcs[n]->amount_msat;
if (!funding_delta(o2, o1, oa, 0, -amount,
amount = cstate->b.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o2), oa->amount,
0, -amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -194,8 +204,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_timedout_htlc->r_hash);
if (n == tal_count(cstate->a.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->a.htlcs[n]->amount_msat;
if (!funding_delta(o1, o2, oa, 0, -amount,
amount = cstate->a.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o1), oa->amount,
0, -amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -214,8 +225,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_routefail_htlc->r_hash);
if (n == tal_count(cstate->a.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->a.htlcs[n]->amount_msat;
if (!funding_delta(o1, o2, oa, 0, -amount,
amount = cstate->a.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o1), oa->amount,
0, -amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -225,8 +237,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_routefail_htlc->r_hash);
if (n == tal_count(cstate->b.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->b.htlcs[n]->amount_msat;
if (!funding_delta(o2, o1, oa, 0, -amount,
amount = cstate->b.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o2), oa->amount,
0, -amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -253,8 +266,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
n = find_htlc(&cstate->a, rh);
if (n == tal_count(cstate->a.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->a.htlcs[n]->amount_msat;
if (!funding_delta(o1, o2, oa, -amount, -amount,
amount = cstate->a.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o1), oa->amount,
-amount, -amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -266,8 +280,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
n = find_htlc(&cstate->b, rh);
if (n == tal_count(cstate->b.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->b.htlcs[n]->amount_msat;
if (!funding_delta(o2, o1, oa, -amount, -amount,
amount = cstate->b.htlcs[n].msatoshis;
if (!funding_delta(is_funder(o2), oa->amount,
-amount, -amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
(long long)amount, *argv);
@ -285,7 +300,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
delta = -pkt->update->delta_msat;
else
delta = pkt->update->delta_msat;
if (!funding_delta(o1, o2, oa, delta, 0,
if (!funding_delta(is_funder(o1), oa->amount, delta, 0,
&cstate->a, &cstate->b))
errx(1, "Impossible funding update %lli %s",
(long long)delta, *argv);

View File

@ -15,4 +15,13 @@ struct channel_state *gather_updates(const tal_t *ctx,
struct sha256 *our_rhash,
struct sha256 *their_rhash,
struct signature *their_commit_sig);
/**
* is_funder: helper to tell you if this is offering to fund channel.
* @o: the openchannel packet.
*/
static inline bool is_funder(const OpenChannel *o)
{
return o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR;
}
#endif /* GATHER_UPDATES_H */

View File

@ -9,6 +9,7 @@
#include "bitcoin/base58.h"
#include "pkt.h"
#include "funding.h"
#include "gather_updates.h"
#include "bitcoin/script.h"
#include "bitcoin/address.h"
#include "bitcoin/tx.h"
@ -73,9 +74,14 @@ int main(int argc, char *argv[])
oa.amount = anchor->output[oa.output_index].amount;
/* Figure out initial how much to us, how much to them. */
cstate = initial_funding(ctx, o1, o2, &oa, commit_fee(o1, o2));
if (is_funder(o1) == is_funder(o2))
errx(1, "Must be exactly one funder");
cstate = initial_funding(ctx, is_funder(o1), oa.amount,
commit_fee(o1->commitment_fee,
o2->commitment_fee));
if (!cstate)
errx(1, "Invalid open combination (need 1 anchor offer)");
errx(1, "Invalid open combination (need to cover fees)");
/* Now, create signature for their commitment tx. */
proto_to_sha256(o2->revocation_hash, &rhash);

View File

@ -16,6 +16,7 @@
#include "bitcoin/privkey.h"
#include "protobuf_convert.h"
#include "funding.h"
#include "gather_updates.h"
#include "version.h"
#include <unistd.h>
@ -56,13 +57,17 @@ int main(int argc, char *argv[])
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]);
if (is_funder(o1) == is_funder(o2))
errx(1, "Must be exactly one funder");
/* Now create THEIR commitment tx to spend 2/2 output of anchor. */
cstate = initial_funding(ctx, o1, o2, a, commit_fee(o1, o2));
cstate = initial_funding(ctx, is_funder(o2), a->amount,
commit_fee(o2->commitment_fee,
o1->commitment_fee));
if (!cstate)
errx(1, "Invalid open combination (need 1 anchor offer)");
errx(1, "Invalid open combination (too low for fees)");
proto_to_sha256(o2->revocation_hash, &rhash);
invert_cstate(cstate);
commit = commit_tx_from_pkts(ctx, o2, o1, a, &rhash, cstate);
/* If contributions don't exceed fees, this fails. */

View File

@ -63,7 +63,10 @@ int main(int argc, char *argv[])
errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Figure out cumulative delta since anchor. */
cstate = gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 6,
cstate = gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee,
o2->commitment_fee),
argv + 6,
&num_updates, NULL, &their_rhash, NULL);
/* Get next revocation hash. */

View File

@ -58,7 +58,10 @@ int main(int argc, char *argv[])
sig.stype = SIGHASH_ALL;
/* This also checks that preimage is correct! */
cstate = gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 5,
cstate = gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee,
o2->commitment_fee),
argv + 5,
&num_updates,
&our_rhash, &their_rhash, &sig.sig);
if (num_updates < 1)

View File

@ -65,7 +65,10 @@ int main(int argc, char *argv[])
sig.stype = SIGHASH_ALL;
/* Figure out cumulative delta since anchor. */
cstate = gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 6,
cstate = gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee,
o2->commitment_fee),
argv + 6,
&num_updates,
&our_rhash, &their_rhash, &sig.sig);
if (num_updates < 1)