script

package
v2.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 11, 2025 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	OP_0           = 0x00 // 将数字0推入栈
	OP_DATA_1      = 0x01 // 将接下来的1个字节作为数据推入栈
	OP_DATA_2      = 0x02 // 将接下来的2个字节作为数据推入栈
	OP_DATA_3      = 0x03 // 将接下来的3个字节作为数据推入栈
	OP_DATA_4      = 0x04 // 将接下来的4个字节作为数据推入栈
	OP_DATA_5      = 0x05 // 将接下来的5个字节作为数据推入栈
	OP_DATA_6      = 0x06 // 将接下来的6个字节作为数据推入栈
	OP_DATA_7      = 0x07 // 将接下来的7个字节作为数据推入栈
	OP_DATA_8      = 0x08 // 将接下来的8个字节作为数据推入栈
	OP_DATA_9      = 0x09 // 将接下来的9个字节作为数据推入栈
	OP_DATA_10     = 0x0a // 将接下来的10个字节作为数据推入栈
	OP_DATA_11     = 0x0b // 将接下来的11个字节作为数据推入栈
	OP_DATA_12     = 0x0c // 将接下来的12个字节作为数据推入栈
	OP_DATA_13     = 0x0d // 将接下来的13个字节作为数据推入栈
	OP_DATA_14     = 0x0e // 将接下来的14个字节作为数据推入栈
	OP_DATA_15     = 0x0f // 将接下来的15个字节作为数据推入栈
	OP_DATA_16     = 0x10 // 将接下来的16个字节作为数据推入栈
	OP_DATA_17     = 0x11 // 将接下来的17个字节作为数据推入栈
	OP_DATA_18     = 0x12 // 将接下来的18个字节作为数据推入栈
	OP_DATA_19     = 0x13 // 将接下来的19个字节作为数据推入栈
	OP_DATA_20     = 0x14 // 将接下来的20个字节作为数据推入栈
	OP_DATA_21     = 0x15 // 将接下来的21个字节作为数据推入栈
	OP_DATA_22     = 0x16 // 将接下来的22个字节作为数据推入栈
	OP_DATA_23     = 0x17 // 将接下来的23个字节作为数据推入栈
	OP_DATA_24     = 0x18 // 将接下来的24个字节作为数据推入栈
	OP_DATA_25     = 0x19 // 将接下来的25个字节作为数据推入栈
	OP_DATA_26     = 0x1a // 将接下来的26个字节作为数据推入栈
	OP_DATA_27     = 0x1b // 将接下来的27个字节作为数据推入栈
	OP_DATA_28     = 0x1c // 将接下来的28个字节作为数据推入栈
	OP_DATA_29     = 0x1d // 将接下来的29个字节作为数据推入栈
	OP_DATA_30     = 0x1e // 将接下来的30个字节作为数据推入栈
	OP_DATA_31     = 0x1f // 将接下来的31个字节作为数据推入栈
	OP_DATA_32     = 0x20 // 将接下来的32个字节作为数据推入栈
	OP_DATA_33     = 0x21 // 将接下来的33个字节作为数据推入栈
	OP_DATA_34     = 0x22 // 将接下来的34个字节作为数据推入栈
	OP_DATA_35     = 0x23 // 将接下来的35个字节作为数据推入栈
	OP_DATA_36     = 0x24 // 将接下来的36个字节作为数据推入栈
	OP_DATA_37     = 0x25 // 将接下来的37个字节作为数据推入栈
	OP_DATA_38     = 0x26 // 将接下来的38个字节作为数据推入栈
	OP_DATA_39     = 0x27 // 将接下来的39个字节作为数据推入栈
	OP_DATA_40     = 0x28 // 将接下来的40个字节作为数据推入栈
	OP_DATA_41     = 0x29 // 将接下来的41个字节作为数据推入栈
	OP_DATA_42     = 0x2a // 将接下来的42个字节作为数据推入栈
	OP_DATA_43     = 0x2b // 将接下来的43个字节作为数据推入栈
	OP_DATA_44     = 0x2c // 将接下来的44个字节作为数据推入栈
	OP_DATA_45     = 0x2d // 将接下来的45个字节作为数据推入栈
	OP_DATA_46     = 0x2e // 将接下来的46个字节作为数据推入栈
	OP_DATA_47     = 0x2f // 将接下来的47个字节作为数据推入栈
	OP_DATA_48     = 0x30 // 将接下来的48个字节作为数据推入栈
	OP_DATA_49     = 0x31 // 将接下来的49个字节作为数据推入栈
	OP_DATA_50     = 0x32 // 将接下来的50个字节作为数据推入栈
	OP_DATA_51     = 0x33 // 将接下来的51个字节作为数据推入栈
	OP_DATA_52     = 0x34 // 将接下来的52个字节作为数据推入栈
	OP_DATA_53     = 0x35 // 将接下来的53个字节作为数据推入栈
	OP_DATA_54     = 0x36 // 将接下来的54个字节作为数据推入栈
	OP_DATA_55     = 0x37 // 将接下来的55个字节作为数据推入栈
	OP_DATA_56     = 0x38 // 将接下来的56个字节作为数据推入栈
	OP_DATA_57     = 0x39 // 将接下来的57个字节作为数据推入栈
	OP_DATA_58     = 0x3a // 将接下来的58个字节作为数据推入栈
	OP_DATA_59     = 0x3b // 将接下来的59个字节作为数据推入栈
	OP_DATA_60     = 0x3c // 将接下来的60个字节作为数据推入栈
	OP_DATA_61     = 0x3d // 将接下来的61个字节作为数据推入栈
	OP_DATA_62     = 0x3e // 将接下来的62个字节作为数据推入栈
	OP_DATA_63     = 0x3f // 将接下来的63个字节作为数据推入栈
	OP_DATA_64     = 0x40 // 将接下来的64个字节作为数据推入栈
	OP_DATA_65     = 0x41 // 将接下来的65个字节作为数据推入栈
	OP_DATA_66     = 0x42 // 将接下来的66个字节作为数据推入栈
	OP_DATA_67     = 0x43 // 将接下来的67个字节作为数据推入栈
	OP_DATA_68     = 0x44 // 将接下来的68个字节作为数据推入栈
	OP_DATA_69     = 0x45 // 将接下来的69个字节作为数据推入栈
	OP_DATA_70     = 0x46 // 将接下来的70个字节作为数据推入栈
	OP_DATA_71     = 0x47 // 将接下来的71个字节作为数据推入栈
	OP_DATA_72     = 0x48 // 将接下来的72个字节作为数据推入栈
	OP_DATA_73     = 0x49 // 将接下来的73个字节作为数据推入栈
	OP_DATA_74     = 0x4a // 将接下来的74个字节作为数据推入栈
	OP_DATA_75     = 0x4b // 将接下来的75个字节作为数据推入栈
	OP_1           = 0x51 // 将数字1推入栈
	OP_PUSHDATA1   = 0x4c // 接下来的一个字节表示要推入栈的数据长度
	OP_PUSHDATA2   = 0x4d // 接下来的两个字节表示要推入栈的数据长度
	OP_PUSHDATA4   = 0x4e // 接下来的四个字节表示要推入栈的数据长度
	OP_1NEGATE     = 0x4f // 将数字-1推入栈
	OP_DUP         = 0x76 // 复制栈顶元素
	OP_HASH160     = 0xa9 // 对栈顶元素进行SHA-256然后RIPEMD-160哈希
	OP_CHECKSIG    = 0xac // 验证交易签名
	OP_EQUALVERIFY = 0x88 // 检查栈顶两个元素是否相等,如果相等则移除它们,否则失败
)

这些常量是比特币脚本中使用的标准操作码。 每个常量代表一个特定的操作或指令。

View Source
const (
	OpCondFalse = 0 // 条件为假
	OpCondTrue  = 1 // 条件为真
	OpCondSkip  = 2 // 跳过条件
)

Conditional 执行常数。 这些常量用于条件操作码的执行控制。

View Source
const HashSize = 32

HashSize 定义了哈希值的大小,通常是双重 SHA256 哈希的大小。

View Source
const (
	// MaxScriptElementSize 定义可推入堆栈的最大字节数
	MaxScriptElementSize = 520
)

定义脚本相关的常量

View Source
const (
	// MaxScriptSize 是原始脚本允许的最大长度
	MaxScriptSize = 10000
)

Variables

This section is empty.

Functions

func CompressPubKey

func CompressPubKey(pubKey *ecdsa.PublicKey) []byte

CompressPubKey 获取压缩格式的公钥 参数:

  • pubKey: 要压缩的ECDSA公钥

返回:

  • []byte: 压缩后的公钥字节切片

处理逻辑:

  1. 获取公钥的X坐标
  2. 根据Y坐标的奇偶性确定前缀
  3. 将前缀和X坐标组合成压缩公钥

func DecompressPubKey

func DecompressPubKey(curve elliptic.Curve, compressedPubKey []byte) (*ecdsa.PublicKey, error)

DecompressPubKey 从压缩公钥解压得到完整的公钥 参数:

  • curve: 使用的椭圆曲线
  • compressedPubKey: 压缩格式的公钥字节切片

返回:

  • *ecdsa.PublicKey: 解压后的ECDSA公钥
  • error: 解压过程中的错误,如果没有错误则为nil

func DisasmString

func DisasmString(script []byte) (string, error)

DisasmString 将脚本反汇编为一行字符串 参数:

  • script: 要反汇编的脚本字节切片

返回:

  • string: 反汇编后的字符串
  • error: 解析过程中的错误,如果没有错误则为nil

注意: 此函数仅适用于版本0的脚本

func DisassembleScript

func DisassembleScript(script []byte) string

DisassembleScript 反汇编脚本并以易读的格式返回 参数:

  • script: 要反汇编的脚本字节切片

返回:

  • string: 反汇编后的脚本字符串,操作码和数据以空格分隔

处理逻辑:

  1. 遍历脚本字节
  2. 识别每个字节代表的操作码或数据
  3. 将操作码转换为可读字符串
  4. 对于数据推送操作,提取并编码数据
  5. 将所有解析结果拼接成一个字符串

func ExtractPubKeyFromP2PKScriptToECDSA

func ExtractPubKeyFromP2PKScriptToECDSA(p2pkScript []byte) (*ecdsa.PublicKey, error)

ExtractPubKeyFromP2PKScriptToECDSA 从P2PK脚本中提取ECDSA公钥 参数:

  • p2pkScript: P2PK脚本的字节切片

返回:

  • *ecdsa.PublicKey: 提取的ECDSA公钥
  • error: 提取过程中的错误,如果没有错误则为nil

func ExtractPubKeyFromP2PKScriptToRSA

func ExtractPubKeyFromP2PKScriptToRSA(p2pkScript []byte) (*rsa.PublicKey, error)

ExtractPubKeyFromP2PKScriptToRSA 从P2PK脚本中提取RSA公钥 参数:

  • p2pkScript: P2PK 公钥脚本的字节切片

返回:

  • *rsa.PublicKey: 提取的RSA公钥
  • error: 提取过程中的错误,如果没有错误则为nil

处理逻辑:

  1. 验证脚本长度和结构
  2. 提取公钥字节
  3. 解析公钥字节为PKIX格式
  4. 将解析结果转换为RSA公钥

func ExtractPubKeyHashFromP2PKScript

func ExtractPubKeyHashFromP2PKScript(p2pkScript []byte) ([]byte, error)

ExtractPubKeyHashFromP2PKScript 从 P2PK 脚本中提取公钥哈希 参数:

  • p2pkScript: P2PK 公钥脚本的字节切片

返回:

  • []byte: 提取的公钥哈希
  • error: 提取过程中的错误,如果没有错误则为nil

处理逻辑:

  1. 验证脚本长度和结构
  2. 提取公钥字节
  3. 对公钥进行SHA256哈希
  4. 对SHA256哈希结果进行RIPEMD160哈希

func ExtractPubKeyHashFromScript

func ExtractPubKeyHashFromScript(script []byte) ([]byte, error)

ExtractPubKeyHashFromScript 从P2PKH脚本中提取公钥哈希 参数:

  • script: P2PKH 脚本的字节切片

返回:

  • []byte: 提取的公钥哈希
  • error: 提取过程中的错误,如果没有错误则为nil

处理逻辑:

  1. 验证脚本长度
  2. 从脚本中提取公钥哈希部分(通常是第3到第22个字节)

func IsPayToPubKeyHash

func IsPayToPubKeyHash(script []byte) bool

IsPayToPubKeyHash 检查脚本是否为标准的支付公钥哈希(P2PKH)格式 参数:

  • script: 要检查的脚本字节切片

返回:

  • bool: 如果是P2PKH格式则返回true,否则返回false

func MakeScriptNum

func MakeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum, error)

MakeScriptNum 将传递的序列化字节解释为编码整数,并将结果作为脚本编号返回。

由于共识规则规定解释为 int 的序列化字节只允许在最大字节数确定的范围内,因此在每个操作码的基础上,当提供的字节导致超出范围的数字时,将返回错误 那个范围的。 特别是,绝大多数处理数值的操作码的范围仅限于 4 个字节,因此会将该值传递给此函数,从而产生 [-2^31 + 1, 2^31 - 1] 的允许范围。

如果对编码的额外检查确定它没有用尽可能小的字节数表示或者是负 0 编码 [0x80],则 requireMinimal 标志会导致返回错误。 例如,考虑数字 127。它可以编码为 [0x7f]、[0x7f 0x00]、[0x7f 0x00 0x00 ...] 等。除了 [0x7f] 之外的所有形式都将在启用 requireMinimal 的情况下返回错误。

scriptNumLen 是在返回 ErrStackNumberTooBig 之前编码值可以达到的最大字节数。 这有效地限制了允许值的范围。 警告:如果传递大于 maxScriptNumLen 的值,应格外小心,这可能导致加法和乘法溢出。

有关示例编码,请参阅 Bytes 函数文档。

func VerifyScriptPubKeyHash

func VerifyScriptPubKeyHash(script, pubKeyHash []byte) bool

VerifyScriptPubKeyHash 验证脚本中的公钥哈希是否与给定的PubKeyHash匹配 参数:

  • script: 要验证的脚本字节切片
  • pubKeyHash: 要匹配的公钥哈希

返回:

  • bool: 如果匹配则返回true,否则返回false

Types

type CryptoAlgorithm

type CryptoAlgorithm interface {
	Hash(data []byte) []byte
	VerifySignature(signature, message, publicKey []byte) bool
}

CryptoAlgorithm 定义了加密算法的接口

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine 是一个通用脚本执行引擎的结构体

type ErrScriptNotCanonical

type ErrScriptNotCanonical string

ErrScriptNotCanonical 标识非规范脚本。 调用者可以使用类型断言来检测此错误类型。

func (ErrScriptNotCanonical) Error

func (e ErrScriptNotCanonical) Error() string

Error 实现错误接口。

type ExecutionEnvironment

type ExecutionEnvironment interface {
	GetExternalData(key string) ([]byte, error)
	CallExternalAPI(api string, params ...interface{}) ([]byte, error)
}

ExecutionEnvironment 定义了脚本执行环境的接口,允许脚本与外部系统交互

type Hash

type Hash [HashSize]byte

Hash 用于多个消息和常见结构中,通常代表数据的双重 sha256 哈希。

type ResourceLimiter

type ResourceLimiter struct {
	MaxExecutionTime int64 // 最大执行时间(单位:纳秒)
	MaxMemoryUsage   int64 // 最大内存使用量(单位:字节)
}

ResourceLimiter 用于限制脚本执行的资源使用

type ScriptBuilder

type ScriptBuilder struct {
	// contains filtered or unexported fields
}

ScriptBuilder 提供了构建自定义脚本的工具。 它允许您在遵守规范编码的同时推送操作码、整数和数据。 一般来说,它不能确保脚本正确执行,但是任何超出脚本引擎允许的最大限制并因此保证不执行的数据推送都不会被推送,并将导致脚本函数返回错误。

例如,以下代码将构建一个 2-of-3 多重签名脚本,用于支付脚本哈希(尽管在这种情况下 MultiSigScript() 是生成脚本的更好选择):

builder := NewScriptBuilder()
builder.AddOp(OP_2).AddData(pubKey1).AddData(pubKey2)
builder.AddData(pubKey3).AddOp(OP_3)
builder.AddOp(OP_CHECKMULTISIG)
script, err := builder.Script()
if err != nil {
	// Handle the error.
	return
}
logger.Printf("Final multi-sig script: %x\n", script)

func NewScriptBuilder

func NewScriptBuilder(opts ...ScriptBuilderOpt) *ScriptBuilder

NewScriptBuilder 返回脚本生成器的新实例。 有关详细信息,请参阅 ScriptBuilder。

func (*ScriptBuilder) AddData

func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder

AddData 将传递的数据推送到脚本末尾。 它根据数据的长度自动选择规范操作码。 零长度缓冲区将导致将空数据推送到堆栈 (OP_0),并且任何大于 MaxScriptElementSize 的数据推送都不会修改脚本,因为脚本引擎不允许这样做。 此外,如果推送数据会导致脚本超出脚本引擎允许的最大大小,则不会修改脚本。

func (*ScriptBuilder) AddFullData

func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder

AddFullData 通常不应该由普通用户使用,因为它不包括防止数据推送大于允许的最大大小的检查,从而导致脚本无法执行。 这是为了测试目的而提供的,例如故意将大小设置为大于允许的大小的回归测试。

使用 AddData 代替。

func (*ScriptBuilder) AddInt64

func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder

AddInt64 将传递的整数推送到脚本末尾。 如果推送数据会导致脚本超出脚本引擎允许的最大大小,则不会修改脚本。

func (*ScriptBuilder) AddOp

func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder

AddOp 将传递的操作码推送到脚本末尾。 如果推送操作码会导致脚本超出允许的最大脚本引擎大小,则不会修改脚本。

func (*ScriptBuilder) AddOps

func (b *ScriptBuilder) AddOps(opcodes []byte) *ScriptBuilder

AddOps 将传递的操作码推送到脚本的末尾。 如果推送操作码会导致脚本超出允许的最大脚本引擎大小,则不会修改脚本。

func (*ScriptBuilder) Reset

func (b *ScriptBuilder) Reset() *ScriptBuilder

Reset 重置脚本,使其没有内容。

func (*ScriptBuilder) Script

func (b *ScriptBuilder) Script() ([]byte, error)

脚本返回当前构建的脚本。 当构建脚本时发生任何错误时,脚本将与错误一起返回到第一个错误点。

type ScriptBuilderOpt

type ScriptBuilderOpt func(*scriptBuilderConfig)

ScriptBuilderOpt 是一种函数选项类型,用于修改 ScriptBuilder 的初始化。

func WithScriptAllocSize

func WithScriptAllocSize(size int) ScriptBuilderOpt

WithScriptAllocSize 指定脚本生成器的支持数组的初始大小。

type ScriptFlags

type ScriptFlags uint32

ScriptFlags 是一个位掩码,定义执行脚本对时将完成的附加操作或测试

type ScriptTokenizer

type ScriptTokenizer struct {
	// contains filtered or unexported fields
}

ScriptTokenizer 提供了一种无需创建分配即可轻松高效地标记交易脚本的工具。 每个连续的操作码都使用 Next 函数进行解析,迭代完成后返回 false,这可能是由于成功标记整个脚本或遇到解析错误。 在失败的情况下,可以使用Err函数来获取具体的解析错误。

成功解析操作码后,可以分别通过 Opcode 和 Data 函数获取与其关联的操作码和数据。

ByteIndex 函数可用于获取分词器在原始脚本中的当前偏移量。

func MakeScriptTokenizer

func MakeScriptTokenizer(scriptVersion uint16, script []byte) ScriptTokenizer

MakeScriptTokenizer 返回脚本标记生成器的新实例。 传递不受支持的脚本版本将导致返回的标记生成器立即相应地设置错误。

有关更多详细信息,请参阅 ScriptTokenizer 的文档。

func (*ScriptTokenizer) ByteIndex

func (t *ScriptTokenizer) ByteIndex() int32

ByteIndex 将当前偏移量返回到接下来将被解析的完整脚本中,因此也暗示了解析之前的所有内容。

func (*ScriptTokenizer) Data

func (t *ScriptTokenizer) Data() []byte

Data 返回与最近成功解析的操作码关联的数据。

func (*ScriptTokenizer) Done

func (t *ScriptTokenizer) Done() bool

Done 当所有操作码都已用尽或遇到解析失败并且因此状态有关联错误时返回 true。

func (*ScriptTokenizer) Err

func (t *ScriptTokenizer) Err() error

Err 返回当前与标记生成器关联的任何错误。 仅当遇到解析错误时,该值才为非零。

func (*ScriptTokenizer) Next

func (t *ScriptTokenizer) Next() bool

Next 尝试解析下一个操作码并返回是否成功。 如果在脚本末尾调用、遇到解析失败或由于先前的解析失败而已存在关联错误,则不会成功。

在返回 true 的情况下,可以使用关联函数获取解析的操作码和数据,并且如果解析了最终操作码,则脚本中的偏移量将指向下一个操作码或脚本的末尾。

在返回错误的情况下,解析的操作码和数据将是最后成功解析的值(如果有),并且脚本中的偏移量将指向失败的操作码或脚本的末尾(如果调用函数) 当已经在脚本末尾时。

当已经位于脚本末尾时调用此函数不会被视为错误,只会返回 false。

func (*ScriptTokenizer) Opcode

func (t *ScriptTokenizer) Opcode() byte

Opcode 返回与分词器关联的当前操作码。

func (*ScriptTokenizer) OpcodePosition

func (t *ScriptTokenizer) OpcodePosition() int32

OpcodePosition 返回当前操作码计数器。 与上面的 ByteIndex(有时称为程序计数器或 pc)不同,它随着每个节点操作码而递增,并且对于推送数据不会递增多次。

注意:如果没有解析任何操作码,则返回 -1。

func (*ScriptTokenizer) Script

func (t *ScriptTokenizer) Script() []byte

Script 返回与分词器关联的完整脚本。

type SigCache

type SigCache struct {
	sync.RWMutex // 读写锁,用于保证并发访问安全
	// contains filtered or unexported fields
}

SigCache 实现了一个结合了Schnorr和ECDSA签名验证的缓存,采用随机条目驱逐策略。 只有有效的签名才会被添加到缓存中。SigCache的好处有两方面: 首先,使用SigCache可以缓解一种DoS攻击,攻击会导致受害者的客户端由于处理攻击者 构造的无效交易时触发的最坏情况行为而挂起。关于被缓解的DoS攻击的详细描述可以在此处找到: https://bitslogger.wordpress.com/2013/01/23/fixed-bitcoin-vulnerability-explanation-why-the-signature-cache-is-a-dos-protection/。 其次,使用SigCache引入了签名验证优化,如果交易已经在mempool中被看到并验证过, 则可以加速区块中交易的验证。

func NewSigCache

func NewSigCache(maxEntries uint) *SigCache

NewSigCache 创建并初始化一个新的 SigCache 实例。 参数 'maxEntries' 表示在任何特定时刻,SigCache中允许存在的最大条目数。 当新条目会导致缓存中的条目数超过最大值时,将随机逐出条目以腾出空间。

func (*SigCache) Add

func (s *SigCache) Add(sigHash Hash, sig []byte, pubKey []byte)

Add 向签名缓存中添加一个签名 'sig' 在 'sigHash' 下的条目,该签名使用公钥 'pubKey'。 如果 SigCache 已满,则随机选择一个现有条目进行逐出,以便为新条目腾出空间。

注意:这个函数是并发安全的。写入者将阻塞同时的读取者,直到函数执行完成。

func (*SigCache) Exists

func (s *SigCache) Exists(sigHash Hash, sig []byte, pubKey []byte) bool

Exists 检查是否存在一个针对公钥 'pubKey' 的签名 'sig' 在 SigCache 中的条目。 如果找到,则返回 true;否则返回 false。

注意:这个函数是并发安全的。读取操作不会被阻塞,除非有写入者正在添加条目到 SigCache。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL