Bitcoin-Crypto

 view release on metacpan or  search on metacpan

lib/Bitcoin/Crypto/Transaction/Digest.pm  view on Meta::CPAN

			taproot_ext_flag
			taproot_ext
			taproot_annex
		)
	],
);

has field '_cache' => (
	isa => HashRef,
	default => sub { {} },
);

sub get_digest
{
	my ($self) = @_;
	my $input = $self->transaction->inputs->[$self->signing_index];

	Bitcoin::Crypto::Exception::Transaction->raise(
		"can't find input with index " . $self->signing_index
	) unless $input;

	my $procedure = '_get_digest_default';
	if ($input->is_taproot) {
		$procedure = '_get_digest_taproot';
	}
	elsif ($input->is_segwit) {
		$procedure = '_get_digest_segwit';
	}

	return $self->$procedure();
}

sub _get_digest_default
{
	my ($self) = @_;

	my $sighash = $self->_default_sighash(SIGHASH_ALL);

	my $sighash_type = $sighash & 31;
	my $anyonecanpay = $sighash & SIGHASH_ANYONECANPAY;

	my $transaction = $self->transaction;
	my $tx_copy = $transaction->clone;

	my $signing_index = $self->signing_index;
	my $inputs = $transaction->inputs;
	my $copy_inputs = $tx_copy->inputs;
	@{$copy_inputs} = ();

	foreach my $input_ind (keys @{$inputs}) {

		# no other inputs if anyonecanpay - skip cloning and all other work
		next if $anyonecanpay && $input_ind != $signing_index;

		my $input = $inputs->[$input_ind]->clone;

		if ($input_ind == $signing_index) {
			my $subscript = $self->signing_subscript;
			if (!$subscript) {
				Bitcoin::Crypto::Exception::Transaction->raise(
					"can't guess the subscript from a non-standard transaction"
				) unless $input->utxo->output->is_standard;

				$subscript = $input->script_base;
			}

			$input->set_signature_script($subscript);
		}
		else {
			$input->set_signature_script('');
			$input->set_sequence_no(0)
				if $sighash_type == SIGHASH_NONE
				|| $sighash_type == SIGHASH_SINGLE;
		}

		push @{$copy_inputs}, $input;
	}

	# Handle output work for sighashes
	if ($sighash_type == SIGHASH_NONE) {
		@{$tx_copy->outputs} = ();
	}
	elsif ($sighash_type == SIGHASH_SINGLE) {
		my $outputs = $transaction->outputs;
		my $copy_outputs = $tx_copy->outputs;
		@{$copy_outputs} = ();

		if ($signing_index >= @{$outputs}) {

			# this should verify with constant digest (without hashing)
			return Bitcoin::Crypto::Transaction::Digest::Result->new(
				hash => scalar reverse ensure_length("\x01", 32),
			);
		}

		foreach my $output (@{$outputs}[0 .. $signing_index - 1]) {
			my $output_copy = $output->clone;
			$output_copy->set_locking_script('');
			$output_copy->set_max_value;
			push @{$copy_outputs}, $output_copy;
		}

		push @{$copy_outputs}, $outputs->[$signing_index];
	}

	my $serialized = $tx_copy->to_serialized(witness => 0);
	$serialized .= pack 'V', $sighash;

	return Bitcoin::Crypto::Transaction::Digest::Result->new(preimage => $serialized);
}

sub _get_digest_segwit
{
	my ($self) = @_;

	my $sighash = $self->_default_sighash(SIGHASH_ALL);

	my $sighash_type = $sighash & 31;
	my $anyonecanpay = $sighash & SIGHASH_ANYONECANPAY;

	my $signing_index = $self->signing_index;



( run in 1.129 second using v1.01-cache-2.11-cpan-39bf76dae61 )