-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
task.vrf.go
117 lines (106 loc) · 4 KB
/
task.vrf.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
109
110
111
112
113
114
115
116
117
package pipeline
import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"go.uber.org/multierr"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey"
"github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1"
"github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof"
)
type VRFTask struct {
BaseTask `mapstructure:",squash"`
PublicKey string `json:"publicKey"`
RequestBlockHash string `json:"requestBlockHash"`
RequestBlockNumber string `json:"requestBlockNumber"`
Topics string `json:"topics"`
keyStore VRFKeyStore
}
type VRFKeyStore interface {
GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error)
}
var _ Task = (*VRFTask)(nil)
func (t *VRFTask) Type() TaskType {
return TaskTypeVRF
}
func (t *VRFTask) Run(_ context.Context, _ logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) {
if len(inputs) != 1 {
return Result{Error: ErrWrongInputCardinality}, runInfo
}
if inputs[0].Error != nil {
return Result{Error: ErrInputTaskErrored}, runInfo
}
logValues, ok := inputs[0].Value.(map[string]interface{})
if !ok {
return Result{Error: errors.Wrap(ErrBadInput, "expected map input")}, runInfo
}
var (
pubKey BytesParam
requestBlockHash BytesParam
requestBlockNumber Uint64Param
topics HashSliceParam
)
err := multierr.Combine(
errors.Wrap(ResolveParam(&pubKey, From(VarExpr(t.PublicKey, vars))), "publicKey"),
errors.Wrap(ResolveParam(&requestBlockHash, From(VarExpr(t.RequestBlockHash, vars))), "requestBlockHash"),
errors.Wrap(ResolveParam(&requestBlockNumber, From(VarExpr(t.RequestBlockNumber, vars))), "requestBlockNumber"),
errors.Wrap(ResolveParam(&topics, From(VarExpr(t.Topics, vars))), "topics"),
)
if err != nil {
return Result{Error: err}, runInfo
}
requestKeyHash, ok := logValues["keyHash"].([32]byte)
if !ok {
return Result{Error: errors.Wrapf(ErrBadInput, "invalid keyHash")}, runInfo
}
requestPreSeed, ok := logValues["seed"].(*big.Int)
if !ok {
return Result{Error: errors.Wrapf(ErrBadInput, "invalid preSeed")}, runInfo
}
requestJobID, ok := logValues["jobID"].([32]byte)
if !ok {
return Result{Error: errors.Wrapf(ErrBadInput, "invalid requestJobID")}, runInfo
}
pk, err := secp256k1.NewPublicKeyFromBytes(pubKey)
if err != nil {
return Result{Error: fmt.Errorf("failed to create PublicKey from bytes %v", err)}, runInfo
}
pkh := pk.MustHash()
// Validate the key against the spec
if !bytes.Equal(requestKeyHash[:], pkh[:]) {
return Result{Error: fmt.Errorf("invalid key hash %v expected %v", hex.EncodeToString(requestKeyHash[:]), hex.EncodeToString(pkh[:]))}, runInfo
}
preSeed, err := proof.BigToSeed(requestPreSeed)
if err != nil {
return Result{Error: fmt.Errorf("unable to parse preseed %v", preSeed)}, runInfo
}
if !bytes.Equal(topics[0][:], requestJobID[:]) && !bytes.Equal(topics[1][:], requestJobID[:]) {
return Result{Error: fmt.Errorf("request jobID %v doesn't match expected %v or %v", requestJobID[:], topics[0][:], topics[1][:])}, runInfo
}
if len(requestBlockHash) != common.HashLength {
return Result{Error: fmt.Errorf("invalid BlockHash length %d expected %d", len(requestBlockHash), common.HashLength)}, runInfo
}
preSeedData := proof.PreSeedData{
PreSeed: preSeed,
BlockHash: common.BytesToHash(requestBlockHash),
BlockNum: uint64(requestBlockNumber),
}
finalSeed := proof.FinalSeed(preSeedData)
p, err := t.keyStore.GenerateProof(pk.String(), finalSeed)
if err != nil {
return Result{Error: err}, runInfo
}
onChainProof, err := proof.GenerateProofResponseFromProof(p, preSeedData)
if err != nil {
return Result{Error: err}, retryableRunInfo()
}
var results = make(map[string]interface{})
results["onChainProof"] = hexutil.Encode(onChainProof[:])
return Result{Value: hexutil.Encode(onChainProof[:])}, runInfo
}