#include "config.h"
#include <ccan/array_size/array_size.h>
#include <ccan/time/time.h>
#include <common/daemon.h>
#include <common/setup.h>
#include <common/status.h>
#include <stdio.h>

#undef status_debug
#define status_debug(...)

#define main unused_main
int main(int argc, char *argv[]);
#include "../onchaind.c"
#undef main

/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_hsmd_get_per_commitment_point_reply */
bool fromwire_hsmd_get_per_commitment_point_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *per_commitment_point UNNEEDED, struct secret **old_commitment_secret UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_get_per_commitment_point_reply called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_depth */
bool fromwire_onchaind_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_depth called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_dev_memleak */
bool fromwire_onchaind_dev_memleak(const void *p UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_dev_memleak called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_htlcs */
bool fromwire_onchaind_htlcs(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct htlc_stub **htlc UNNEEDED, bool **tell_if_missing UNNEEDED, bool **tell_immediately UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_htlcs called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_init */
bool fromwire_onchaind_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct amount_msat *our_msat UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct tx_parts **tx_parts UNNEEDED, u32 *locktime UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey *local_funding_pubkey UNNEEDED, struct pubkey *remote_funding_pubkey UNNEEDED, u64 *local_static_remotekey_start UNNEEDED, u64 *remote_static_remotekey_start UNNEEDED, bool *option_anchor_outputs UNNEEDED, bool *option_anchors_zero_fee_htlc_tx UNNEEDED, u32 *min_relay_feerate UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_init called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_known_preimage */
bool fromwire_onchaind_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_known_preimage called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_spend_created */
bool fromwire_onchaind_spend_created(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *expect_to_succeed UNNEEDED, struct onchain_witness_element ***witness UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_spend_created called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_spent */
bool fromwire_onchaind_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct tx_parts **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_spent called!\n"); abort(); }
/* Generated stub for onchaind_wire_name */
const char *onchaind_wire_name(int e UNNEEDED)
{ fprintf(stderr, "onchaind_wire_name called!\n"); abort(); }
/* Generated stub for towire_hsmd_get_per_commitment_point */
u8 *towire_hsmd_get_per_commitment_point(const tal_t *ctx UNNEEDED, u64 n UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_per_commitment_point called!\n"); abort(); }
/* Generated stub for towire_onchaind_add_utxo */
u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *prev_out UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED, u32 csv_lock UNNEEDED)
{ fprintf(stderr, "towire_onchaind_add_utxo called!\n"); abort(); }
/* Generated stub for towire_onchaind_all_irrevocably_resolved */
u8 *towire_onchaind_all_irrevocably_resolved(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_onchaind_all_irrevocably_resolved called!\n"); abort(); }
/* Generated stub for towire_onchaind_annotate_txin */
u8 *towire_onchaind_annotate_txin(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, u32 innum UNNEEDED, enum wallet_tx_type type UNNEEDED)
{ fprintf(stderr, "towire_onchaind_annotate_txin called!\n"); abort(); }
/* Generated stub for towire_onchaind_annotate_txout */
u8 *towire_onchaind_annotate_txout(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, enum wallet_tx_type type UNNEEDED)
{ fprintf(stderr, "towire_onchaind_annotate_txout called!\n"); abort(); }
/* Generated stub for towire_onchaind_dev_memleak_reply */
u8 *towire_onchaind_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEEDED)
{ fprintf(stderr, "towire_onchaind_dev_memleak_reply called!\n"); abort(); }
/* Generated stub for towire_onchaind_extracted_preimage */
u8 *towire_onchaind_extracted_preimage(const tal_t *ctx UNNEEDED, const struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "towire_onchaind_extracted_preimage called!\n"); abort(); }
/* Generated stub for towire_onchaind_htlc_timeout */
u8 *towire_onchaind_htlc_timeout(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
{ fprintf(stderr, "towire_onchaind_htlc_timeout called!\n"); abort(); }
/* Generated stub for towire_onchaind_init_reply */
u8 *towire_onchaind_init_reply(const tal_t *ctx UNNEEDED, u64 commit_num UNNEEDED)
{ fprintf(stderr, "towire_onchaind_init_reply called!\n"); abort(); }
/* Generated stub for towire_onchaind_missing_htlc_output */
u8 *towire_onchaind_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
{ fprintf(stderr, "towire_onchaind_missing_htlc_output called!\n"); abort(); }
/* Generated stub for towire_onchaind_notify_coin_mvt */
u8 *towire_onchaind_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED)
{ fprintf(stderr, "towire_onchaind_notify_coin_mvt called!\n"); abort(); }
/* Generated stub for towire_onchaind_notify_penalty_adj */
u8 *towire_onchaind_notify_penalty_adj(const tal_t *ctx UNNEEDED, struct amount_msat amount UNNEEDED)
{ fprintf(stderr, "towire_onchaind_notify_penalty_adj called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_fulfill */
u8 *towire_onchaind_spend_fulfill(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u64 htlc_id UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_fulfill called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_htlc_expired */
u8 *towire_onchaind_spend_htlc_expired(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u64 htlc_id UNNEEDED, u32 cltv_expiry UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_htlc_expired called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_htlc_success */
u8 *towire_onchaind_spend_htlc_success(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, struct amount_sat fee UNNEEDED, u64 htlc_id UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_signature *remote_htlc_sig UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED, const u8 *htlc_wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_htlc_success called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_htlc_timeout */
u8 *towire_onchaind_spend_htlc_timeout(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, struct amount_sat fee UNNEEDED, u64 htlc_id UNNEEDED, u32 cltv_expiry UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_signature *remote_htlc_sig UNNEEDED, const u8 *wscript UNNEEDED, const u8 *htlc_wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_htlc_timeout called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_penalty */
u8 *towire_onchaind_spend_penalty(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, const struct secret *remote_per_commitment_secret UNNEEDED, const u8 *stack_elem UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_penalty called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_to_us */
u8 *towire_onchaind_spend_to_us(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u32 sequence UNNEEDED, u32 minblock UNNEEDED, u64 commit_num UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_to_us called!\n"); abort(); }
/* Generated stub for towire_onchaind_spent_reply */
u8 *towire_onchaind_spent_reply(const tal_t *ctx UNNEEDED, bool interested UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spent_reply called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

int main(int argc, char *argv[])
{
	common_setup(argv[0]);

	struct bitcoin_tx *tx;
	struct bitcoin_signature sig;
	u8 *der, *wscript;
	struct amount_sat fee;
	struct pubkey htlc_key;
	struct keyset *keys;
	struct timemono start, end;
	int iterations = 1000;
	u8 *spk = tal_arr(tmpctx, u8, 1);
	spk[0] = 0x00;

	chainparams = chainparams_for_network("bitcoin");
	tx = bitcoin_tx_from_hex(tmpctx, "0200000001e1ebca08cf1c301ac563580a1126d5c8fcb0e5e2043230b852c726553caf1e1d0000000000000000000160ae0a000000000022002082e03c5a9cb79c82cd5a0572dc175290bc044609aabe9cc852d61927436041796d000000",
				 strlen("0200000001e1ebca08cf1c301ac563580a1126d5c8fcb0e5e2043230b852c726553caf1e1d0000000000000000000160ae0a000000000022002082e03c5a9cb79c82cd5a0572dc175290bc044609aabe9cc852d61927436041796d000000"));
	tx->chainparams = chainparams_for_network("regtest");
	psbt_input_set_wit_utxo(tx->psbt, 0, spk, AMOUNT_SAT(700000));
	tx->chainparams = chainparams_for_network("bitcoin");
	der = tal_hexdata(tmpctx, "30450221009b2e0eef267b94c3899fb0dc7375012e2cee4c10348a068fe78d1b82b4b14036022077c3fad3adac2ddf33f415e45f0daf6658b7a0b09647de4443938ae2dbafe2b9" "01",
			  strlen("30450221009b2e0eef267b94c3899fb0dc7375012e2cee4c10348a068fe78d1b82b4b14036022077c3fad3adac2ddf33f415e45f0daf6658b7a0b09647de4443938ae2dbafe2b9" "01"));
	if (!signature_from_der(der, tal_count(der), &sig))
		abort();

	wscript = tal_hexdata(tmpctx, "76a914a8c40c334351dbe8e5908544f1c98fbcfb8719fc8763ac6721038ffd2621647812011960152bfb79c5a2787dfe6c4f37e2222547de054432eb7f7c820120876475527c2103cf8e2f193a6aed60db80af75f3c8d59c2de735b299b7c7083527be9bd23b77a852ae67a914b8bcd51efa35be1e50ae2d5f72f4500acb005c9c88ac6868", strlen("76a914a8c40c334351dbe8e5908544f1c98fbcfb8719fc8763ac6721038ffd2621647812011960152bfb79c5a2787dfe6c4f37e2222547de054432eb7f7c820120876475527c2103cf8e2f193a6aed60db80af75f3c8d59c2de735b299b7c7083527be9bd23b77a852ae67a914b8bcd51efa35be1e50ae2d5f72f4500acb005c9c88ac6868"));
	if (!pubkey_from_hexstr("038ffd2621647812011960152bfb79c5a2787dfe6c4f37e2222547de054432eb7f",
				strlen("038ffd2621647812011960152bfb79c5a2787dfe6c4f37e2222547de054432eb7f"),
				&htlc_key))
		abort();

	/* Dance around a little because keyset is const */
	keys = tal(tmpctx, struct keyset);
	keys->other_htlc_key = htlc_key;
	keyset = keys;

	if (argc > 1)
		iterations = atoi(argv[1]);
	max_possible_feerate = 250000;
	min_possible_feerate = max_possible_feerate + 1 - iterations;

	start = time_mono();
	if (!grind_htlc_tx_fee(&fee, tx, &sig, wscript, 663))
		abort();
	end = time_mono();
	assert(amount_sat_eq(fee, AMOUNT_SAT(165750)));
	printf("%u iterations in %"PRIu64" msec = %"PRIu64" nsec each\n",
	       iterations,
	       time_to_msec(timemono_between(end, start)),
	       time_to_nsec(time_divide(timemono_between(end, start), iterations)));

	common_shutdown();
	return 0;
}
