forked from arkade-os/emulator
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintent.go
More file actions
93 lines (75 loc) · 2.68 KB
/
Copy pathintent.go
File metadata and controls
93 lines (75 loc) · 2.68 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
package application
import (
"context"
"fmt"
"time"
"github.com/ArkLabsHQ/introspector/pkg/arkade"
"github.com/arkade-os/arkd/pkg/ark-lib/intent"
"github.com/btcsuite/btcd/btcutil/psbt"
log "github.com/sirupsen/logrus"
)
// SubmitIntent aims to execute arkade scripts on unsigned intent proof
// it must be used before registration of the intent
func (s *service) SubmitIntent(ctx context.Context, intent Intent) (*psbt.Packet, error) {
if err := validateRegisterMessage(intent.Message); err != nil {
return nil, fmt.Errorf("invalid message: %w", err)
}
ptx := &intent.Proof.Packet
prevoutFetcher, err := computePrevoutFetcher(ptx)
if err != nil {
return nil, fmt.Errorf("failed to create prevout fetcher: %w", err)
}
// Parse IntrospectorPacket from the transaction's OP_RETURN output
packet, err := arkade.FindIntrospectorPacket(ptx.UnsignedTx)
if err != nil {
return nil, fmt.Errorf("failed to parse introspector packet: %w", err)
}
if len(packet) == 0 {
return nil, fmt.Errorf("no introspector packet found in transaction")
}
signerPublicKey := s.signer.secretKey.PubKey()
for _, entry := range packet {
inputIndex := int(entry.Vin)
if inputIndex == 0 {
// in intent proof, input index 0 is the message input
// the signature script equals to the input 1 script
// so we can skip it and handle it later if input index 1 is an arkade script
continue
}
script, err := arkade.ReadArkadeScript(ptx, signerPublicKey, entry)
if err != nil {
// skip if the input is not a valid arkade script
continue
}
if err := script.Execute(ptx.UnsignedTx, prevoutFetcher, inputIndex); err != nil {
log.WithError(err).WithField("input_index", inputIndex).Error("arkade script execution failed")
return nil, fmt.Errorf("failed to execute arkade script at input %d: %w", inputIndex, err)
}
if err := s.signer.signInput(ptx, inputIndex, script.Hash(), prevoutFetcher); err != nil {
return nil, fmt.Errorf("failed to sign input %d: %w", inputIndex, err)
}
// if input index 1 is valid and signed, we can also sign the intent message input (index 0)
if inputIndex == 1 {
if err := s.signer.signInput(ptx, 0, script.Hash(), prevoutFetcher); err != nil {
return nil, fmt.Errorf("failed to sign fake message input: %w", err)
}
}
}
return ptx, nil
}
func validateRegisterMessage(message intent.RegisterMessage) error {
now := time.Now()
if message.ExpireAt > 0 {
expireAt := time.Unix(message.ExpireAt, 0)
if expireAt.Before(now) {
return fmt.Errorf("intent message expired")
}
}
if message.ValidAt > 0 {
validAt := time.Unix(message.ValidAt, 0)
if validAt.After(now) {
return fmt.Errorf("intent message not valid yet")
}
}
return nil
}