diff --git a/Makefile b/Makefile index f4dab5fa9..40f9d2073 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ TEST_PROGRAMS := \ BITCOIN_OBJS := \ bitcoin/address.o \ bitcoin/base58.o \ + bitcoin/locktime.o \ bitcoin/pubkey.o \ bitcoin/script.o \ bitcoin/shadouble.o \ diff --git a/bitcoin/locktime.c b/bitcoin/locktime.c new file mode 100644 index 000000000..05b7ad2b1 --- /dev/null +++ b/bitcoin/locktime.c @@ -0,0 +1,101 @@ +#include "bitcoin/locktime.h" +#include + +/* Alpha uses simple locktimes a-la the tx locktime field; BIP68 uses + * a bitmask */ +#define SECONDS_POINT 500000000 + +#define BIP68_SECONDS_FLAG (1<<22) +#define BIP68_LOCKTIME_MASK (0x0000FFFF) +#define BIP68_SECONDS_SHIFT 9 + +static bool abs_seconds_to_locktime(u32 seconds, u32 *locktime) +{ + *locktime = seconds; + if (*locktime < SECONDS_POINT) + return false; + return true; +} + +static bool abs_blocks_to_locktime(u32 blocks, u32 *locktime) +{ + *locktime = blocks; + if (*locktime >= SECONDS_POINT) + return false; + return true; +} + +static bool abs_is_seconds(u32 locktime) +{ + return locktime >= SECONDS_POINT; +} + +bool seconds_to_rel_locktime(u32 seconds, struct rel_locktime *rel) +{ +#ifdef HAS_BIP68 + if ((seconds >> BIP68_SECONDS_SHIFT) > BIP68_LOCKTIME_MASK) + return false; + rel->locktime = BIP68_SECONDS_FLAG | (seconds >> BIP68_SECONDS_SHIFT); + return true; +#else + /* Make abs-style time by adding SECONDS_POINT. */ + return abs_seconds_to_locktime(seconds + SECONDS_POINT, &rel->locktime); +#endif +} + +bool blocks_to_rel_locktime(u32 blocks, struct rel_locktime *rel) +{ +#ifdef HAS_BIP68 + if (blocks > BIP68_LOCKTIME_MASK) + return false; +#endif + rel->locktime = blocks; + return true; +} + +bool rel_locktime_is_seconds(const struct rel_locktime *rel) +{ +#ifdef HAS_BIP68 + return rel->locktime & BIP68_SECONDS_FLAG; +#else + return abs_is_seconds(rel->locktime); +#endif +} + +u32 rel_locktime_to_seconds(const struct rel_locktime *rel) +{ + assert(rel_locktime_is_seconds(rel)); +#ifdef HAS_BIP68 + return rel->locktime & BIP68_LOCKTIME_MASK; +#else + return rel->locktime - SECONDS_POINT; +#endif +} + +u32 bitcoin_nsequence(const struct rel_locktime *rel) +{ +#ifdef HAS_BIP68 + /* Can't set disable bit, or other bits except low 16 and bit 22 */ + assert(!(rel->locktime & ~(BIP68_SECONDS_FLAG|BIP68_LOCKTIME_MASK))); + return rel->locktime; +#else + /* Alpha uses the original proposal: simply invert the bits. */ + return ~rel->locktime; +#endif +} + +bool seconds_to_abs_locktime(u32 seconds, struct abs_locktime *abs) +{ + return abs_seconds_to_locktime(seconds, &abs->locktime); +} + +bool blocks_to_abs_locktime(u32 blocks, struct abs_locktime *abs) +{ + return abs_blocks_to_locktime(blocks, &abs->locktime); +} + +bool abs_locktime_is_seconds(const struct abs_locktime *abs) +{ + return abs_is_seconds(abs->locktime); +} + diff --git a/bitcoin/locktime.h b/bitcoin/locktime.h new file mode 100644 index 000000000..9ebbc65cf --- /dev/null +++ b/bitcoin/locktime.h @@ -0,0 +1,27 @@ +#ifndef LIGHTNING_BITCOIN_LOCKTIME_H +#define LIGHTNING_BITCOIN_LOCKTIME_H +#include +#include + +/* As used by nSequence and OP_CHECKSEQUENCEVERIFY (BIP68) */ +struct rel_locktime { + u32 locktime; +}; + +bool seconds_to_rel_locktime(u32 seconds, struct rel_locktime *rel); +bool blocks_to_rel_locktime(u32 blocks, struct rel_locktime *rel); +bool rel_locktime_is_seconds(const struct rel_locktime *rel); +u32 rel_locktime_to_seconds(const struct rel_locktime *rel); + +u32 bitcoin_nsequence(const struct rel_locktime *rel); + +/* As used by nLocktime and OP_CHECKLOCKTIMEVERIFY (BIP65) */ +struct abs_locktime { + u32 locktime; +}; + +bool seconds_to_abs_locktime(u32 seconds, struct abs_locktime *abs); +bool blocks_to_abs_locktime(u32 blocks, struct abs_locktime *abs); +bool abs_locktime_is_seconds(const struct abs_locktime *abs); + +#endif /* LIGHTNING_BITCOIN_LOCKTIME_H */ diff --git a/bitcoin/script.c b/bitcoin/script.c index ca13b6f34..fd5df82d1 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -3,6 +3,7 @@ #include #include #include "address.h" +#include "locktime.h" #include "pubkey.h" #include "script.h" #include "signature.h" @@ -179,8 +180,8 @@ u8 *scriptpubkey_p2sh(const tal_t *ctx, const u8 *redeemscript) u8 *scriptpubkey_htlc_send(const tal_t *ctx, const struct pubkey *ourkey, const struct pubkey *theirkey, - uint32_t htlc_abstimeout, - uint32_t locktime, + const struct abs_locktime *htlc_abstimeout, + const struct rel_locktime *locktime, const struct sha256 *commit_revoke, const struct sha256 *rhash) { @@ -210,9 +211,9 @@ u8 *scriptpubkey_htlc_send(const tal_t *ctx, add_op(&script, OP_ELSE); /* If HTLC times out, they can collect after a delay. */ - add_number(&script, htlc_abstimeout); + add_number(&script, htlc_abstimeout->locktime); add_op(&script, OP_CHECKLOCKTIMEVERIFY); - add_number(&script, locktime); + add_number(&script, locktime->locktime); add_op(&script, OP_CHECKSEQUENCEVERIFY); add_op(&script, OP_2DROP); add_push_key(&script, ourkey); @@ -227,8 +228,8 @@ u8 *scriptpubkey_htlc_send(const tal_t *ctx, u8 *scriptpubkey_htlc_recv(const tal_t *ctx, const struct pubkey *ourkey, const struct pubkey *theirkey, - uint32_t htlc_abstimeout, - uint32_t locktime, + const struct abs_locktime *htlc_abstimeout, + const struct rel_locktime *locktime, const struct sha256 *commit_revoke, const struct sha256 *rhash) { @@ -247,7 +248,7 @@ u8 *scriptpubkey_htlc_recv(const tal_t *ctx, add_op(&script, OP_EQUAL); add_op(&script, OP_IF); - add_number(&script, locktime); + add_number(&script, locktime->locktime); add_op(&script, OP_CHECKSEQUENCEVERIFY); /* Drop extra hash as well as locktime. */ add_op(&script, OP_2DROP); @@ -264,7 +265,7 @@ u8 *scriptpubkey_htlc_recv(const tal_t *ctx, add_op(&script, OP_NOTIF); /* Otherwise, they must wait for HTLC timeout. */ - add_number(&script, htlc_abstimeout); + add_number(&script, htlc_abstimeout->locktime); add_op(&script, OP_CHECKLOCKTIMEVERIFY); add_op(&script, OP_DROP); add_op(&script, OP_ENDIF); @@ -361,7 +362,7 @@ bool is_p2sh(const u8 *script, size_t script_len) * it after delay. */ u8 *bitcoin_redeem_secret_or_delay(const tal_t *ctx, const struct pubkey *delayed_key, - u32 locktime, + const struct rel_locktime *locktime, const struct pubkey *key_if_secret_known, const struct sha256 *hash_of_secret) { @@ -382,7 +383,7 @@ u8 *bitcoin_redeem_secret_or_delay(const tal_t *ctx, add_op(&script, OP_ELSE); /* Other can collect after a delay. */ - add_number(&script, locktime); + add_number(&script, locktime->locktime); add_op(&script, OP_CHECKSEQUENCEVERIFY); add_op(&script, OP_DROP); add_push_key(&script, delayed_key); diff --git a/bitcoin/script.h b/bitcoin/script.h index 641e754af..2a671450a 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -7,6 +7,8 @@ struct bitcoin_address; struct pubkey; struct sha256; +struct rel_locktime; +struct abs_locktime; /* A bitcoin signature includes one byte for the type. */ struct bitcoin_signature { @@ -26,7 +28,7 @@ u8 *bitcoin_redeem_single(const tal_t *ctx, const struct pubkey *key); * it after delay. */ u8 *bitcoin_redeem_secret_or_delay(const tal_t *ctx, const struct pubkey *delayed_key, - u32 locktime, + const struct rel_locktime *locktime, const struct pubkey *key_if_secret_known, const struct sha256 *hash_of_secret); @@ -41,8 +43,8 @@ u8 *scriptsig_pay_to_pubkeyhash(const tal_t *ctx, u8 *scriptpubkey_htlc_send(const tal_t *ctx, const struct pubkey *ourkey, const struct pubkey *theirkey, - uint32_t htlc_abstimeout, - uint32_t locktime, + const struct abs_locktime *htlc_abstimeout, + const struct rel_locktime *locktime, const struct sha256 *commit_revoke, const struct sha256 *rhash); @@ -50,8 +52,8 @@ u8 *scriptpubkey_htlc_send(const tal_t *ctx, u8 *scriptpubkey_htlc_recv(const tal_t *ctx, const struct pubkey *ourkey, const struct pubkey *theirkey, - uint32_t htlc_abstimeout, - uint32_t locktime, + const struct abs_locktime *htlc_abstimeout, + const struct rel_locktime *locktime, const struct sha256 *commit_revoke, const struct sha256 *rhash); diff --git a/bitcoin/tx.c b/bitcoin/tx.c index fb3546970..d352abcb3 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -546,17 +546,3 @@ bool bitcoin_tx_write(int fd, const struct bitcoin_tx *tx) tal_free(tx_arr); return ok; } - -u32 bitcoin_nsequence(u32 locktime) -{ -#ifdef HAS_BIP68 - /* FIXME: return fail to caller. */ - /* Can't set disable bit, or other bits except low 16 and bit 22 */ - assert(!(locktime & ~((1 << 22) | 0xFFFF))); - return locktime; -#else - /* Alpha uses the original proposal: simply invert the bits. */ - return ~locktime; -#endif -} - diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 841100fac..ad8ecd51e 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -66,6 +66,4 @@ bool bitcoin_txid_from_hex(const char *hexstr, size_t hexstr_len, bool bitcoin_txid_to_hex(const struct sha256_double *txid, char *hexstr, size_t hexstr_len); -/* Get sequence number for a given locktime. */ -u32 bitcoin_nsequence(u32 locktime); #endif /* LIGHTNING_BITCOIN_TX_H */ diff --git a/commit_tx.c b/commit_tx.c index ee8d560af..3b1a753dc 100644 --- a/commit_tx.c +++ b/commit_tx.c @@ -1,3 +1,4 @@ +#include "bitcoin/locktime.h" #include "bitcoin/pubkey.h" #include "bitcoin/script.h" #include "bitcoin/shadouble.h" @@ -14,16 +15,16 @@ static bool add_htlc(struct bitcoin_tx *tx, size_t n, const struct pubkey *ourkey, const struct pubkey *theirkey, const struct sha256 *rhash, - u32 locktime, + const struct rel_locktime *locktime, u8 *(*scriptpubkeyfn)(const tal_t *, const struct pubkey *, const struct pubkey *, - uint32_t, - uint32_t, + const struct abs_locktime *, + const struct rel_locktime *, const struct sha256 *, const struct sha256 *)) { - uint32_t htlc_abstime; + struct abs_locktime htlc_abstime; struct sha256 htlc_rhash; assert(!tx->output[n].script); @@ -35,7 +36,7 @@ static bool add_htlc(struct bitcoin_tx *tx, size_t n, proto_to_sha256(h->r_hash, &htlc_rhash); tx->output[n].script = scriptpubkey_p2sh(tx, scriptpubkeyfn(tx, ourkey, theirkey, - htlc_abstime, locktime, rhash, + &htlc_abstime, locktime, rhash, &htlc_rhash)); tx->output[n].script_length = tal_count(tx->output[n].script); tx->output[n].amount = h->amount_msat / 1000; @@ -52,7 +53,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx, struct bitcoin_tx *tx; const u8 *redeemscript; struct pubkey ourkey, theirkey; - u32 locktime; + struct rel_locktime locktime; size_t i, num; uint64_t total; @@ -76,7 +77,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx, /* First output is a P2SH to a complex redeem script (usu. for me) */ redeemscript = bitcoin_redeem_secret_or_delay(tx, &ourkey, - locktime, + &locktime, &theirkey, rhash); tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); @@ -97,14 +98,14 @@ 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], &ourkey, &theirkey, - rhash, locktime, scriptpubkey_htlc_send)) + rhash, &locktime, scriptpubkey_htlc_send)) return tal_free(tx); total += tx->output[num++].amount; } /* HTLCs we've received. */ for (i = 0; i < tal_count(cstate->b.htlcs); i++) { if (!add_htlc(tx, num, cstate->b.htlcs[i], &ourkey, &theirkey, - rhash, locktime, scriptpubkey_htlc_recv)) + rhash, &locktime, scriptpubkey_htlc_recv)) return tal_free(tx); total += tx->output[num++].amount; } diff --git a/protobuf_convert.c b/protobuf_convert.c index 99577fe72..d98777a87 100644 --- a/protobuf_convert.c +++ b/protobuf_convert.c @@ -1,4 +1,5 @@ #include +#include "bitcoin/locktime.h" #include "bitcoin/pubkey.h" #include "bitcoin/signature.h" #include "protobuf_convert.h" @@ -105,54 +106,26 @@ void proto_to_sha256(const Sha256Hash *pb, struct sha256 *hash) memcpy(hash->u.u8 + 24, &pb->d, 8); } -static bool proto_to_locktime(const Locktime *l, uint32_t off, - uint32_t *locktime) +bool proto_to_rel_locktime(const Locktime *l, struct rel_locktime *locktime) { switch (l->locktime_case) { case LOCKTIME__LOCKTIME_SECONDS: - *locktime = off + l->seconds; - /* Check for wrap, or too low value */ - if (*locktime < 500000000) - return false; - break; + return seconds_to_rel_locktime(l->seconds, locktime); case LOCKTIME__LOCKTIME_BLOCKS: - if (l->blocks >= 500000000) - return false; - *locktime = l->blocks; - break; + return blocks_to_rel_locktime(l->blocks, locktime); default: return false; } - return true; } -bool proto_to_rel_locktime(const Locktime *l, uint32_t *locktime) +bool proto_to_abs_locktime(const Locktime *l, struct abs_locktime *locktime) { - /* Original proposal from Elements Alpha was simply locktime. */ -#ifdef HAS_BIP68 switch (l->locktime_case) { case LOCKTIME__LOCKTIME_SECONDS: - *locktime = (1 << 22) | (l->seconds / 512); - if (l->seconds / 512 > 0xFFFF) - return false; - break; + return seconds_to_abs_locktime(l->seconds, locktime); case LOCKTIME__LOCKTIME_BLOCKS: - *locktime = l->blocks; - if (l->blocks > 0xFFFF) - return false; - break; + return blocks_to_abs_locktime(l->blocks, locktime); default: return false; } - /* No other bits should be set. */ - assert((*locktime & ~((1 << 22) | 0xFFFF)) == 0); - return true; -#else - return proto_to_locktime(l, 500000000, locktime); -#endif -} - -bool proto_to_abs_locktime(const Locktime *l, uint32_t *locktime) -{ - return proto_to_locktime(l, 0, locktime); } diff --git a/protobuf_convert.h b/protobuf_convert.h index 98713e5f7..ee0d95c36 100644 --- a/protobuf_convert.h +++ b/protobuf_convert.h @@ -19,6 +19,8 @@ struct sha256; Sha256Hash *sha256_to_proto(const tal_t *ctx, const struct sha256 *hash); void proto_to_sha256(const Sha256Hash *pb, struct sha256 *hash); -bool proto_to_rel_locktime(const Locktime *l, uint32_t *locktime); -bool proto_to_abs_locktime(const Locktime *l, uint32_t *locktime); +struct rel_locktime; +struct abs_locktime; +bool proto_to_rel_locktime(const Locktime *l, struct rel_locktime *locktime); +bool proto_to_abs_locktime(const Locktime *l, struct abs_locktime *locktime); #endif /* LIGHTNING_PROTOBUF_CONVERT_H */ diff --git a/test-cli/create-commit-spend-tx.c b/test-cli/create-commit-spend-tx.c index 7b49563da..eb90ea275 100644 --- a/test-cli/create-commit-spend-tx.c +++ b/test-cli/create-commit-spend-tx.c @@ -21,6 +21,7 @@ #include "test-cli/gather_updates.h" #include "funding.h" #include "version.h" +#include "bitcoin/locktime.h" #include int main(int argc, char *argv[]) @@ -37,7 +38,7 @@ int main(int argc, char *argv[]) struct sha256 rhash; size_t p2sh_out; u64 fee = 10000; - u32 locktime; + struct rel_locktime locktime; err_set_progname(argv[0]); @@ -87,7 +88,7 @@ int main(int argc, char *argv[]) NULL, &rhash, NULL, NULL); /* Create redeem script */ - redeemscript = bitcoin_redeem_secret_or_delay(ctx, &pubkey1, locktime, + redeemscript = bitcoin_redeem_secret_or_delay(ctx, &pubkey1, &locktime, &pubkey2, &rhash); /* Now, create transaction to spend it. */ @@ -98,7 +99,7 @@ int main(int argc, char *argv[]) tx->input[0].input_amount = commit->output[p2sh_out].amount; tx->fee = fee; - tx->input[0].sequence_number = bitcoin_nsequence(locktime); + tx->input[0].sequence_number = bitcoin_nsequence(&locktime); if (commit->output[p2sh_out].amount <= fee) errx(1, "Amount of %llu won't exceed fee", diff --git a/test-cli/create-htlc-spend-tx.c b/test-cli/create-htlc-spend-tx.c index 0979f0c27..eecad265c 100644 --- a/test-cli/create-htlc-spend-tx.c +++ b/test-cli/create-htlc-spend-tx.c @@ -16,6 +16,7 @@ #include "bitcoin/privkey.h" #include "protobuf_convert.h" #include "find_p2sh_out.h" +#include "bitcoin/locktime.h" #include "version.h" #include @@ -31,7 +32,8 @@ int main(int argc, char *argv[]) struct bitcoin_signature sig; struct privkey privkey; bool testnet; - u32 locktime, htlc_abstimeout; + struct rel_locktime locktime; + struct abs_locktime htlc_abstimeout; char *rvalue = NULL, *preimage = NULL; bool received, own_commit_tx; Pkt *pkt; @@ -114,13 +116,13 @@ int main(int argc, char *argv[]) if (received) { redeemscript = scriptpubkey_htlc_recv(ctx, &pubkey1, &pubkey2, - htlc_abstimeout, - locktime, &revoke_hash, + &htlc_abstimeout, + &locktime, &revoke_hash, &htlc_rhash); } else { redeemscript = scriptpubkey_htlc_send(ctx, &pubkey1, &pubkey2, - htlc_abstimeout, - locktime, &revoke_hash, + &htlc_abstimeout, + &locktime, &revoke_hash, &htlc_rhash); } @@ -163,14 +165,14 @@ int main(int argc, char *argv[]) if (!secret_len) { /* We must be relying on HTLC timeout. */ - tx->lock_time = htlc_abstimeout; + tx->lock_time = htlc_abstimeout.locktime; /* Locktime only applies if an input has seq != ffffffff... */ tx->input[0].sequence_number = 0; } /* If it's our own commit tx, we also need delay. */ if (own_commit_tx) - tx->input[0].sequence_number = bitcoin_nsequence(locktime); + tx->input[0].sequence_number = bitcoin_nsequence(&locktime); /* Leave 10,000 satoshi as fee (if we can!). */ tx->fee = 10000; diff --git a/test-cli/create-steal-tx.c b/test-cli/create-steal-tx.c index 99ab6fd21..07268d25f 100644 --- a/test-cli/create-steal-tx.c +++ b/test-cli/create-steal-tx.c @@ -15,6 +15,7 @@ #include "bitcoin/privkey.h" #include "protobuf_convert.h" #include "version.h" +#include "bitcoin/locktime.h" #include int main(int argc, char *argv[]) @@ -30,7 +31,7 @@ int main(int argc, char *argv[]) struct bitcoin_signature sig; struct privkey privkey; bool testnet; - u32 locktime_seconds; + struct rel_locktime locktime; err_set_progname(argv[0]); @@ -68,7 +69,7 @@ int main(int argc, char *argv[]) o1 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[5], PKT__PKT_OPEN)->open; - if (!proto_to_rel_locktime(o1->delay, &locktime_seconds)) + if (!proto_to_rel_locktime(o1->delay, &locktime)) errx(1, "Invalid locktime in o2"); if (!pubkey_from_hexstr(argv[6], &outpubkey)) @@ -85,7 +86,7 @@ int main(int argc, char *argv[]) /* Now, which commit output? Match redeem script. */ sha256(&revoke_hash, &revoke_preimage, sizeof(revoke_preimage)); redeemscript = bitcoin_redeem_secret_or_delay(ctx, &pubkey2, - locktime_seconds, + &locktime, &pubkey1, &revoke_hash); p2sh = scriptpubkey_p2sh(ctx, redeemscript);