Bitcoin-Crypto
view release on metacpan or search on metacpan
lib/Bitcoin/Crypto/Script.pm view on Meta::CPAN
use Bitcoin::Crypto::Base58 qw(encode_base58check decode_base58check);
use Bitcoin::Crypto::Bech32 qw(encode_segwit decode_segwit get_hrp);
use Bitcoin::Crypto::Constants qw(:witness);
use Bitcoin::Crypto::Util::Internal qw(hash160 hash256 get_address_type to_format);
use Bitcoin::Crypto::Exception;
use Bitcoin::Crypto::Types -types;
use Bitcoin::Crypto::Script::Opcode;
use Bitcoin::Crypto::Script::Runner;
use Bitcoin::Crypto::Script::Compiler;
use Bitcoin::Crypto::Script::Common;
use Bitcoin::Crypto::Script::Recognition;
has field '_serialized' => (
isa => ByteStr,
writer => 1,
default => '',
);
has field '_recognition' => (
isa => InstanceOf ['Bitcoin::Crypto::Script::Recognition'],
lazy => 1,
clearer => -hidden,
handles => {
get_raw_address => 'address',
type => 'type',
segwit_version => 'segwit_version',
},
);
has field '_compiler' => (
isa => InstanceOf ['Bitcoin::Crypto::Script::Compiler'],
lazy => 1,
clearer => -hidden,
handles => {
operations => 'operations',
has_errors => 'has_errors',
assert_valid => 'assert_valid',
},
);
with qw(Bitcoin::Crypto::Role::Network);
sub _build_recognition
{
return Bitcoin::Crypto::Script::Recognition->check(shift);
}
sub _build_compiler
{
return Bitcoin::Crypto::Script::Compiler->compile(shift);
}
sub _build
{
my ($self, $type, $address) = @_;
state $types = do {
my $legacy = sub {
my ($self, $address, $type) = @_;
my $decoded = decode_base58check($address);
my $network_byte = substr $decoded, 0, 1, '';
Bitcoin::Crypto::Exception::Address->raise(
"legacy scripts should contain 20 bytes"
) unless length $decoded == 20;
my $byte_method = lc "p2${type}_byte";
Bitcoin::Crypto::Exception::NetworkCheck->raise(
"provided address $address is not P2$type on network " . $self->network->name
) if $network_byte ne $self->network->$byte_method;
Bitcoin::Crypto::Script::Common->fill($type => $self, $decoded);
};
my $witness = sub {
my ($self, $address, $name, $version, $length) = @_;
my $data = decode_segwit $address;
my $this_version = substr $data, 0, 1, '';
Bitcoin::Crypto::Exception::SegwitProgram->raise(
"$name script only handles witness version $version"
) unless $this_version eq chr $version;
Bitcoin::Crypto::Exception::SegwitProgram->raise(
"$name script should contain $length bytes"
) unless length $data eq $length;
Bitcoin::Crypto::Exception::NetworkCheck->raise(
"provided address $address does not belong to network " . $self->network->name
) if get_hrp($address) ne $self->network->segwit_hrp;
$self
->add("OP_$version")
->push($data);
};
{
P2PK => sub {
my ($self, $pubkey) = @_;
$self
->push($pubkey)
->add('OP_CHECKSIG');
},
P2PKH => sub {
$legacy->(@_, 'PKH');
},
P2SH => sub {
$legacy->(@_, 'SH');
},
P2MS => sub {
my ($self, $data) = @_;
Bitcoin::Crypto::Exception::ScriptPush->raise(
'P2MS script argument must be an array reference'
) unless ref $data eq 'ARRAY';
my ($signatures_num, @pubkeys) = @$data;
Bitcoin::Crypto::Exception::ScriptPush->raise(
'P2MS script first element must be a number between 1 and 15'
) unless $signatures_num >= 0 && $signatures_num <= 15;
Bitcoin::Crypto::Exception::ScriptPush->raise(
'P2MS script remaining elements number should be between the number of signatures and 15'
) unless @pubkeys >= $signatures_num && @pubkeys <= 15;
$self->push(chr $signatures_num);
( run in 1.348 second using v1.01-cache-2.11-cpan-39bf76dae61 )