generated from bitcoin-sv/template
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbitcom.go
More file actions
121 lines (112 loc) · 2.31 KB
/
bitcom.go
File metadata and controls
121 lines (112 loc) · 2.31 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package bitcom
import (
"github.com/bsv-blockchain/go-sdk/script"
)
type Bitcom struct {
Protocols []*BitcomProtocol `json:"protos"`
ScriptPrefix []byte `json:"prefix,omitempty"`
}
type BitcomProtocol struct {
Protocol string `json:"proto"`
Script []byte `json:"script"`
Pos int `json:"pos"`
}
func Decode(scr *script.Script) (bitcom *Bitcom) {
// Handle nil script safely
if scr == nil {
return &Bitcom{
Protocols: []*BitcomProtocol{},
}
}
pos := findReturn(scr)
if pos == -1 {
return bitcom
}
var prefix []byte
if pos > 0 {
prefix = (*scr)[:pos-1]
}
bitcom = &Bitcom{
ScriptPrefix: prefix,
}
pos++
for pos < len(*scr) {
pipePos := findPipe(scr, pos)
p := &BitcomProtocol{
Pos: pos,
}
if op, err := scr.ReadOp(&pos); err != nil {
return bitcom
} else {
p.Protocol = string(op.Data)
}
bitcom.Protocols = append(bitcom.Protocols, p)
if pipePos == -1 {
p.Script = (*scr)[pos:]
break
}
if pipePos < pos {
break
}
p.Script = (*scr)[pos:pipePos]
pos = pipePos + 2
}
return bitcom
}
func (b *Bitcom) Lock() *script.Script {
s := script.NewFromBytes(b.ScriptPrefix)
if len(b.Protocols) > 0 {
_ = s.AppendOpcodes(script.OpRETURN)
for i, p := range b.Protocols {
_ = s.AppendPushData([]byte(p.Protocol))
s = script.NewFromBytes(append(*s, p.Script...))
if i < len(b.Protocols)-1 {
_ = s.AppendPushData([]byte("|"))
}
}
}
return s
}
func findReturn(scr *script.Script) int {
if scr != nil {
i := 0
for i < len(*scr) {
startPos := i
if op, err := scr.ReadOp(&i); err == nil && op.Op == script.OpRETURN {
return startPos
}
}
}
return -1
}
func findPipe(scr *script.Script, from int) int {
if scr != nil {
i := from
for i < len(*scr) {
startPos := i
if op, err := scr.ReadOp(&i); err == nil && op.Op == script.OpDATA1 && op.Data[0] == '|' {
return startPos
}
}
}
return -1
}
// ToScript converts a []byte to a script.Script or returns a script directly
// This is a helper function that can be used by all decoders
func ToScript(data any) *script.Script {
switch d := data.(type) {
case *script.Script:
return d
case script.Script:
return &d
case []byte:
if d == nil {
return nil
}
// Convert bytes to script
s := script.NewFromBytes(d)
return s
default:
return nil
}
}