-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathlocktime.go
108 lines (87 loc) · 2.81 KB
/
locktime.go
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
package common
import (
"fmt"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/txscript"
)
const (
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
SEQUENCE_LOCKTIME_TYPE_FLAG = 1 << 22
SEQUENCE_LOCKTIME_GRANULARITY = 9
SECONDS_MOD = 1 << SEQUENCE_LOCKTIME_GRANULARITY
SECONDS_MAX = SEQUENCE_LOCKTIME_MASK << SEQUENCE_LOCKTIME_GRANULARITY
SEQUENCE_LOCKTIME_DISABLE_FLAG = 1 << 31
SECONDS_PER_BLOCK = 10 * 60 // 10 minutes
// before this value, nLocktime is interpreted as blockheight
nLocktimeMinSeconds = 500_000_000
)
// RelativeLocktimeType represents a BIP68 relative locktime
// it is passed as argument to CheckSequenceVerify opcode
type RelativeLocktimeType uint
const (
LocktimeTypeSecond RelativeLocktimeType = iota
LocktimeTypeBlock
)
// AbsoluteLocktime represents an nLocktime value
// it is used as argument to a CheckLocktimeVerify opcode
type AbsoluteLocktime uint32
func (l AbsoluteLocktime) IsSeconds() bool {
return l >= nLocktimeMinSeconds
}
// RelativeLocktime represents a BIP68 relative timelock value
type RelativeLocktime struct {
Type RelativeLocktimeType
Value uint32
}
func (l RelativeLocktime) Seconds() int64 {
if l.Type == LocktimeTypeBlock {
return int64(l.Value) * SECONDS_PER_BLOCK
}
return int64(l.Value)
}
func (l RelativeLocktime) Compare(other RelativeLocktime) int {
val := l.Seconds()
otherVal := other.Seconds()
if val == otherVal {
return 0
}
if val < otherVal {
return -1
}
return 1
}
// LessThan returns true if this locktime is less than the other locktime
func (l RelativeLocktime) LessThan(other RelativeLocktime) bool {
return l.Compare(other) < 0
}
func BIP68Sequence(locktime RelativeLocktime) (uint32, error) {
value := locktime.Value
isSeconds := locktime.Type == LocktimeTypeSecond
if isSeconds {
if value > SECONDS_MAX {
return 0, fmt.Errorf("seconds too large, max is %d", SECONDS_MAX)
}
if value%SECONDS_MOD != 0 {
return 0, fmt.Errorf("seconds must be a multiple of %d", SECONDS_MOD)
}
}
return blockchain.LockTimeToSequence(isSeconds, value), nil
}
func BIP68DecodeSequence(sequence []byte) (*RelativeLocktime, error) {
scriptNumber, err := txscript.MakeScriptNum(sequence, true, len(sequence))
if err != nil {
return nil, err
}
if scriptNumber >= txscript.OP_1 && scriptNumber <= txscript.OP_16 {
scriptNumber = scriptNumber - (txscript.OP_1 - 1)
}
asNumber := int64(scriptNumber)
if asNumber&SEQUENCE_LOCKTIME_DISABLE_FLAG != 0 {
return nil, fmt.Errorf("sequence is disabled")
}
if asNumber&SEQUENCE_LOCKTIME_TYPE_FLAG != 0 {
seconds := asNumber & SEQUENCE_LOCKTIME_MASK << SEQUENCE_LOCKTIME_GRANULARITY
return &RelativeLocktime{Type: LocktimeTypeSecond, Value: uint32(seconds)}, nil
}
return &RelativeLocktime{Type: LocktimeTypeBlock, Value: uint32(asNumber)}, nil
}