-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpushbytes.go
More file actions
92 lines (86 loc) · 2.16 KB
/
pushbytes.go
File metadata and controls
92 lines (86 loc) · 2.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package outscript
import (
"encoding/binary"
"fmt"
)
// IPushBytes is an [Insertable] that encodes the output of another [Insertable] as a
// Bitcoin script push operation.
type IPushBytes struct {
v Insertable
}
// Bytes generates the inner value and wraps it as a Bitcoin script push operation.
func (i IPushBytes) Bytes(s *Script) ([]byte, error) {
v, err := i.v.Bytes(s)
if err != nil {
return nil, err
}
return PushBytes(v), nil
}
// String returns a human-readable representation of the push operation.
func (i IPushBytes) String() string {
return fmt.Sprintf("PushBytes(%s)", i.v)
}
// PushBytes encodes a byte slice as a Bitcoin script push operation, choosing the
// appropriate opcode (direct push for <=75 bytes, OP_PUSHDATA1/2/4 for larger data).
func PushBytes(v []byte) []byte {
// see: https://en.bitcoin.it/wiki/Script
if len(v) <= 75 {
return append([]byte{byte(len(v))}, v...)
}
if len(v) <= 0xff {
return append([]byte{0x4c, byte(len(v))}, v...) // OP_PUSHDATA1
}
if len(v) <= 0xffff {
var op [3]byte
op[0] = 0x4d // OP_PUSHDATA2
binary.LittleEndian.PutUint16(op[1:], uint16(len(v)))
return append(op[:], v...)
}
// really?
var op [5]byte
op[0] = 0x4e // OP_PUSHDATA4
binary.LittleEndian.PutUint32(op[1:], uint32(len(v)))
return append(op[:], v...)
}
// ParsePushBytes decodes a Bitcoin script push operation at the start of v, returning
// the pushed data and the total number of bytes consumed. It returns (nil, 0) on error.
func ParsePushBytes(v []byte) ([]byte, int) {
if len(v) == 0 {
return nil, 0
}
p := v[0]
v = v[1:]
if p <= 75 {
if len(v) >= int(p) {
return v[:p], int(p) + 1
}
// not enough data → error
return nil, 0
}
switch p {
case 0x4c: // OP_PUSHDATA1
p = v[0]
v = v[1:]
if len(v) >= int(p) {
return v[:p], int(p) + 2
}
// not enough data → error
return nil, 0
case 0x4d: // OP_PUSHDATA2
l := binary.LittleEndian.Uint16(v[:2])
v = v[2:]
if len(v) >= int(l) {
return v[:l], int(l) + 3
}
return nil, 0
case 0x4e: // OP_PUSHDATA4
l := binary.LittleEndian.Uint32(v[:4])
v = v[4:]
if len(v) >= int(l) {
return v[:l], int(l) + 5
}
return nil, 0
default:
return nil, 0
}
}