Implement upgradeability (#151)

* Implement contract upgrade VAA action

* naming and (╯°□°)╯︵ ┻━┻

* Carefully unflip table and replace broken cutlery ┬─┬ノ( ◕◡◕ ノ)

* fix and automate upgradeability

* document contract upgrade call

* Update comments

* Exhaustiveness check in VAA payload switch

* Fix typo

Co-authored-by: Leo <leo@certus.one>
This commit is contained in:
Hendrik Hofstadt 2021-01-19 13:01:45 +01:00 committed by GitHub
parent ad9e8cc45b
commit efa03ef73c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 580 additions and 194 deletions

View File

@ -26,8 +26,7 @@ func init() {
} }
AdminCmd.AddCommand(AdminClientInjectGuardianSetUpdateCmd) AdminCmd.AddCommand(AdminClientInjectGuardianSetUpdateCmd)
AdminCmd.AddCommand(AdminClientGuardianSetTemplateCmd) AdminCmd.AddCommand(AdminClientGovernanceVAAVerifyCmd)
AdminCmd.AddCommand(AdminClientGuardianSetVerifyCmd)
} }
var AdminCmd = &cobra.Command{ var AdminCmd = &cobra.Command{
@ -36,9 +35,9 @@ var AdminCmd = &cobra.Command{
} }
var AdminClientInjectGuardianSetUpdateCmd = &cobra.Command{ var AdminClientInjectGuardianSetUpdateCmd = &cobra.Command{
Use: "guardian-set-update-inject", Use: "governance-vaa-inject",
Short: "Inject and sign a guardian set update from a prototxt file (see docs!)", Short: "Inject and sign a governance VAA from a prototxt file (see docs!)",
Run: runInjectGuardianSetUpdate, Run: runInjectGovernanceVAA,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
} }
@ -53,7 +52,7 @@ func getAdminClient(ctx context.Context, addr string) (*grpc.ClientConn, error,
return conn, err, c return conn, err, c
} }
func runInjectGuardianSetUpdate(cmd *cobra.Command, args []string) { func runInjectGovernanceVAA(cmd *cobra.Command, args []string) {
path := args[0] path := args[0]
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
@ -66,15 +65,15 @@ func runInjectGuardianSetUpdate(cmd *cobra.Command, args []string) {
log.Fatalf("failed to read file: %v", err) log.Fatalf("failed to read file: %v", err)
} }
var msg nodev1.GuardianSetUpdate var msg nodev1.InjectGovernanceVAARequest
err = prototext.Unmarshal(b, &msg) err = prototext.Unmarshal(b, &msg)
if err != nil { if err != nil {
log.Fatalf("failed to deserialize: %v", err) log.Fatalf("failed to deserialize: %v", err)
} }
resp, err := c.SubmitGuardianSetVAA(ctx, &nodev1.SubmitGuardianSetVAARequest{GuardianSet: &msg}) resp, err := c.InjectGovernanceVAA(ctx, &msg)
if err != nil { if err != nil {
log.Fatalf("failed to submit guardian set update: %v", err) log.Fatalf("failed to submit governance VAA: %v", err)
} }
log.Printf("VAA successfully injected with digest %s", hexutils.BytesToHex(resp.Digest)) log.Printf("VAA successfully injected with digest %s", hexutils.BytesToHex(resp.Digest))

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"math"
"net" "net"
"os" "os"
"time" "time"
@ -28,7 +29,7 @@ type nodePrivilegedService struct {
// adminGuardianSetUpdateToVAA converts a nodev1.GuardianSetUpdate message to its canonical VAA representation. // adminGuardianSetUpdateToVAA converts a nodev1.GuardianSetUpdate message to its canonical VAA representation.
// Returns an error if the data is invalid. // Returns an error if the data is invalid.
func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate) (*vaa.VAA, error) { func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate, guardianSetIndex uint32, timestamp uint32) (*vaa.VAA, error) {
if len(req.Guardians) == 0 { if len(req.Guardians) == 0 {
return nil, errors.New("empty guardian set specified") return nil, errors.New("empty guardian set specified")
} }
@ -48,21 +49,59 @@ func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate) (*vaa.VAA, error
v := &vaa.VAA{ v := &vaa.VAA{
Version: vaa.SupportedVAAVersion, Version: vaa.SupportedVAAVersion,
GuardianSetIndex: req.CurrentSetIndex, GuardianSetIndex: guardianSetIndex,
Timestamp: time.Unix(int64(req.Timestamp), 0), Timestamp: time.Unix(int64(timestamp), 0),
Payload: &vaa.BodyGuardianSetUpdate{ Payload: &vaa.BodyGuardianSetUpdate{
Keys: addrs, Keys: addrs,
NewIndex: req.CurrentSetIndex + 1, NewIndex: guardianSetIndex + 1,
}, },
} }
return v, nil return v, nil
} }
func (s *nodePrivilegedService) SubmitGuardianSetVAA(ctx context.Context, req *nodev1.SubmitGuardianSetVAARequest) (*nodev1.SubmitGuardianSetVAAResponse, error) { // adminContractUpgradeToVAA converts a nodev1.ContractUpgrade message to its canonical VAA representation.
s.logger.Info("guardian set injected via admin socket", zap.String("request", req.String())) // Returns an error if the data is invalid.
func adminContractUpgradeToVAA(req *nodev1.ContractUpgrade, guardianSetIndex uint32, timestamp uint32) (*vaa.VAA, error) {
if len(req.NewContract) != 32 {
return nil, errors.New("invalid new_contract address")
}
v, err := adminGuardianSetUpdateToVAA(req.GuardianSet) if req.ChainId > math.MaxUint8 {
return nil, errors.New("invalid chain_id")
}
newContractAddress := vaa.Address{}
copy(newContractAddress[:], req.NewContract)
v := &vaa.VAA{
Version: vaa.SupportedVAAVersion,
GuardianSetIndex: guardianSetIndex,
Timestamp: time.Unix(int64(timestamp), 0),
Payload: &vaa.BodyContractUpgrade{
ChainID: uint8(req.ChainId),
NewContract: newContractAddress,
},
}
return v, nil
}
func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *nodev1.InjectGovernanceVAARequest) (*nodev1.InjectGovernanceVAAResponse, error) {
s.logger.Info("governance VAA injected via admin socket", zap.String("request", req.String()))
var (
v *vaa.VAA
err error
)
switch payload := req.Payload.(type) {
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, req.CurrentSetIndex, req.Timestamp)
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, req.Timestamp)
default:
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
}
if err != nil { if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error()) return nil, status.Error(codes.InvalidArgument, err.Error())
} }
@ -73,14 +112,14 @@ func (s *nodePrivilegedService) SubmitGuardianSetVAA(ctx context.Context, req *n
panic(err) panic(err)
} }
s.logger.Info("guardian set VAA constructed", s.logger.Info("governance VAA constructed",
zap.Any("vaa", v), zap.Any("vaa", v),
zap.String("digest", digest.String()), zap.String("digest", digest.String()),
) )
s.injectC <- v s.injectC <- v
return &nodev1.SubmitGuardianSetVAAResponse{Digest: digest.Bytes()}, nil return &nodev1.InjectGovernanceVAAResponse{Digest: digest.Bytes()}, nil
} }
func adminServiceRunnable(logger *zap.Logger, socketPath string, injectC chan<- *vaa.VAA) (supervisor.Runnable, error) { func adminServiceRunnable(logger *zap.Logger, socketPath string, injectC chan<- *vaa.VAA) (supervisor.Runnable, error) {

View File

@ -13,27 +13,42 @@ import (
nodev1 "github.com/certusone/wormhole/bridge/pkg/proto/node/v1" nodev1 "github.com/certusone/wormhole/bridge/pkg/proto/node/v1"
) )
var templateNumGuardians *int var setUpdateNumGuardians *int
var templateGuardianIndex *int var templateGuardianIndex *int
func init() { func init() {
templateNumGuardians = AdminClientGuardianSetTemplateCmd.Flags().Int("num", 1, "Number of devnet guardians in example file") templateGuardianIndex = TemplateCmd.PersistentFlags().Int("idx", 0, "Default current guardian set index")
templateGuardianIndex = AdminClientGuardianSetTemplateCmd.Flags().Int("idx", 0, "Default current guardian set index") setUpdateNumGuardians = AdminClientGuardianSetTemplateCmd.Flags().Int("num", 1, "Number of devnet guardians in example file")
TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd)
TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd)
}
var TemplateCmd = &cobra.Command{
Use: "template",
Short: "Guardian governance VAA template commands ",
} }
var AdminClientGuardianSetTemplateCmd = &cobra.Command{ var AdminClientGuardianSetTemplateCmd = &cobra.Command{
Use: "guardian-set-update-template", Use: "guardian-set-update",
Short: "Generate an empty guardian set template at specified path (offline)", Short: "Generate an empty guardian set template at specified path (offline)",
Run: runGuardianSetTemplate, Run: runGuardianSetTemplate,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
} }
var AdminClientContractUpgradeTemplateCmd = &cobra.Command{
Use: "contract-upgrade",
Short: "Generate an empty contract upgrade template at specified path (offline)",
Run: runContractUpgradeTemplate,
Args: cobra.ExactArgs(1),
}
func runGuardianSetTemplate(cmd *cobra.Command, args []string) { func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
path := args[0] path := args[0]
// Use deterministic devnet addresses as examples in the template, such that this doubles as a test fixture. // Use deterministic devnet addresses as examples in the template, such that this doubles as a test fixture.
guardians := make([]*nodev1.GuardianSetUpdate_Guardian, *templateNumGuardians) guardians := make([]*nodev1.GuardianSetUpdate_Guardian, *setUpdateNumGuardians)
for i := 0; i < *templateNumGuardians; i++ { for i := 0; i < *setUpdateNumGuardians; i++ {
k := devnet.DeterministicEcdsaKeyByIndex(crypto.S256(), uint64(i)) k := devnet.DeterministicEcdsaKeyByIndex(crypto.S256(), uint64(i))
guardians[i] = &nodev1.GuardianSetUpdate_Guardian{ guardians[i] = &nodev1.GuardianSetUpdate_Guardian{
Pubkey: crypto.PubkeyToAddress(k.PublicKey).Hex(), Pubkey: crypto.PubkeyToAddress(k.PublicKey).Hex(),
@ -41,12 +56,41 @@ func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
} }
} }
m := &nodev1.GuardianSetUpdate{ m := &nodev1.InjectGovernanceVAARequest{
CurrentSetIndex: uint32(*templateGuardianIndex), CurrentSetIndex: uint32(*templateGuardianIndex),
// Timestamp is hardcoded to make it reproducible on different devnet nodes. // Timestamp is hardcoded to make it reproducible on different devnet nodes.
// In production, a real UNIX timestamp should be used (see node.proto). // In production, a real UNIX timestamp should be used (see node.proto).
Timestamp: 1605744545, Timestamp: 1605744545,
Guardians: guardians, Payload: &nodev1.InjectGovernanceVAARequest_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{Guardians: guardians},
},
}
b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m)
if err != nil {
panic(err)
}
err = ioutil.WriteFile(path, b, 0640)
if err != nil {
log.Fatal(err)
}
}
func runContractUpgradeTemplate(cmd *cobra.Command, args []string) {
path := args[0]
m := &nodev1.InjectGovernanceVAARequest{
CurrentSetIndex: uint32(*templateGuardianIndex),
// Timestamp is hardcoded to make it reproducible on different devnet nodes.
// In production, a real UNIX timestamp should be used (see node.proto).
Timestamp: 1605744545,
Payload: &nodev1.InjectGovernanceVAARequest_ContractUpgrade{
ContractUpgrade: &nodev1.ContractUpgrade{
ChainId: 1,
NewContract: make([]byte, 32),
},
},
} }
b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m) b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m)

View File

@ -1,6 +1,7 @@
package guardiand package guardiand
import ( import (
"github.com/certusone/wormhole/bridge/pkg/vaa"
"io/ioutil" "io/ioutil"
"log" "log"
@ -11,14 +12,14 @@ import (
nodev1 "github.com/certusone/wormhole/bridge/pkg/proto/node/v1" nodev1 "github.com/certusone/wormhole/bridge/pkg/proto/node/v1"
) )
var AdminClientGuardianSetVerifyCmd = &cobra.Command{ var AdminClientGovernanceVAAVerifyCmd = &cobra.Command{
Use: "guardian-set-update-verify", Use: "governance-vaa-verify",
Short: "Verify guardian set update in prototxt format (offline)", Short: "Verify governance vaa in prototxt format (offline)",
Run: runGuardianSetVerify, Run: runGovernanceVAAVerify,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
} }
func runGuardianSetVerify(cmd *cobra.Command, args []string) { func runGovernanceVAAVerify(cmd *cobra.Command, args []string) {
path := args[0] path := args[0]
b, err := ioutil.ReadFile(path) b, err := ioutil.ReadFile(path)
@ -26,13 +27,21 @@ func runGuardianSetVerify(cmd *cobra.Command, args []string) {
log.Fatalf("failed to read file: %v", err) log.Fatalf("failed to read file: %v", err)
} }
var msg nodev1.GuardianSetUpdate var msg nodev1.InjectGovernanceVAARequest
err = prototext.Unmarshal(b, &msg) err = prototext.Unmarshal(b, &msg)
if err != nil { if err != nil {
log.Fatalf("failed to deserialize: %v", err) log.Fatalf("failed to deserialize: %v", err)
} }
v, err := adminGuardianSetUpdateToVAA(&msg) var (
v *vaa.VAA
)
switch payload := msg.Payload.(type) {
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, msg.CurrentSetIndex, msg.Timestamp)
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, msg.CurrentSetIndex, msg.Timestamp)
}
if err != nil { if err != nil {
log.Fatalf("invalid update: %v", err) log.Fatalf("invalid update: %v", err)
} }

View File

@ -36,6 +36,7 @@ func init() {
rootCmd.AddCommand(guardiand.BridgeCmd) rootCmd.AddCommand(guardiand.BridgeCmd)
rootCmd.AddCommand(guardiand.KeygenCmd) rootCmd.AddCommand(guardiand.KeygenCmd)
rootCmd.AddCommand(guardiand.AdminCmd) rootCmd.AddCommand(guardiand.AdminCmd)
rootCmd.AddCommand(guardiand.TemplateCmd)
} }
// initConfig reads in config file and ENV variables if set. // initConfig reads in config file and ENV variables if set.

View File

@ -172,6 +172,17 @@ func (p *Processor) handleObservation(ctx context.Context, m *gossipv1.SignedObs
// A guardian set update is broadcast to every chain that we talk to. // A guardian set update is broadcast to every chain that we talk to.
p.devnetVAASubmission(ctx, signed, hash) p.devnetVAASubmission(ctx, signed, hash)
p.terraVAASubmission(ctx, signed, hash) p.terraVAASubmission(ctx, signed, hash)
case *vaa.BodyContractUpgrade:
switch t.ChainID {
case vaa.ChainIDSolana:
// Already submitted to Solana.
default:
p.logger.Error("unsupported target chain for contract upgrade",
zap.String("digest", hash),
zap.Any("vaa", signed),
zap.String("bytes", hex.EncodeToString(vaaBytes)),
zap.Uint8("target_chain", t.ChainID))
}
default: default:
panic(fmt.Sprintf("unknown VAA payload type: %+v", v)) panic(fmt.Sprintf("unknown VAA payload type: %+v", v))
} }

View File

@ -85,6 +85,13 @@ type (
// NewIndex is the index of the new guardian set // NewIndex is the index of the new guardian set
NewIndex uint32 NewIndex uint32
} }
BodyContractUpgrade struct {
// ChainID is the chain on which the contract should be upgraded
ChainID uint8
// NewContract is the address of the account containing the new contract.
NewContract Address
}
) )
func (a Address) String() string { func (a Address) String() string {
@ -106,6 +113,7 @@ func (c ChainID) String() string {
const ( const (
ActionGuardianSetUpdate Action = 0x01 ActionGuardianSetUpdate Action = 0x01
ActionContractUpgrade Action = 0x02
ActionTransfer Action = 0x10 ActionTransfer Action = 0x10
// ChainIDSolana is the ChainID of Solana // ChainIDSolana is the ChainID of Solana
@ -182,6 +190,8 @@ func Unmarshal(data []byte) (*VAA, error) {
v.Payload, err = parseBodyGuardianSetUpdate(payloadReader) v.Payload, err = parseBodyGuardianSetUpdate(payloadReader)
case ActionTransfer: case ActionTransfer:
v.Payload, err = parseBodyTransfer(payloadReader) v.Payload, err = parseBodyTransfer(payloadReader)
case ActionContractUpgrade:
v.Payload, err = parseBodyContractUpgrade(payloadReader)
default: default:
return nil, fmt.Errorf("unknown action: %d", action) return nil, fmt.Errorf("unknown action: %d", action)
} }
@ -403,6 +413,33 @@ func (v *BodyGuardianSetUpdate) serialize() ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func parseBodyContractUpgrade(r io.Reader) (*BodyContractUpgrade, error) {
b := &BodyContractUpgrade{}
if err := binary.Read(r, binary.BigEndian, &b.ChainID); err != nil {
return nil, fmt.Errorf("failed to read chain id: %w", err)
}
if n, err := r.Read(b.NewContract[:]); err != nil || n != 32 {
return nil, fmt.Errorf("failed to read new contract address: %w", err)
}
return b, nil
}
func (v *BodyContractUpgrade) getActionID() Action {
return ActionContractUpgrade
}
func (v *BodyContractUpgrade) serialize() ([]byte, error) {
buf := new(bytes.Buffer)
MustWrite(buf, binary.BigEndian, v.ChainID)
buf.Write(v.NewContract[:])
return buf.Bytes(), nil
}
// MustWrite calls binary.Write and panics on errors // MustWrite calls binary.Write and panics on errors
func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) { func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
if err := binary.Write(w, order, data); err != nil { if err := binary.Write(w, order, data); err != nil {

View File

@ -61,6 +61,24 @@ func TestSerializeDeserialize(t *testing.T) {
}, },
}, },
}, },
{
name: "ContractUpgrade",
vaa: &VAA{
Version: 1,
GuardianSetIndex: 9,
Signatures: []*Signature{
{
Index: 1,
Signature: [65]byte{},
},
},
Timestamp: time.Unix(2837, 0),
Payload: &BodyContractUpgrade{
ChainID: ChainIDEthereum,
NewContract: Address{1, 3, 4, 5, 2, 3},
},
},
},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {

View File

@ -146,6 +146,20 @@ uint8 len(keys)
The `new_index` must be monotonically increasing and is manually specified here to fix a potential guardian_set index The `new_index` must be monotonically increasing and is manually specified here to fix a potential guardian_set index
desynchronization between the any of the chains in the system. desynchronization between the any of the chains in the system.
##### Contract upgrade
ID: `0x02`
Payload:
```
uint8 chain_id
[32]uint8 new_contract
```
`chain_id` specifies the chain on which the contract should be updated. `new_contract` is the address of the updated
contract.
##### Transfer ##### Transfer
ID: `0x10` ID: `0x10`

View File

@ -154,6 +154,14 @@ followed by:
| ----- | ------------ | ------------------- | ------ | --------- | ----- | ------- | | ----- | ------------ | ------------------- | ------ | --------- | ----- | ------- |
| 9 | guardian_set_new | GuardianSet | | ✅ | ✅ | ✅ | | 9 | guardian_set_new | GuardianSet | | ✅ | ✅ | ✅ |
##### Contract upgrade
| Index | Name | Type | signer | writeable | empty | derived |
| ----- | ------------------ | ----------------- | ------ | --------- | ----- | ------- |
| 9 | new_contract | Account | | | ✅ | |
| 10 | program_data | Account | | ✅ | ✅ | ✅ |
| 11 | upgradeable_loader | UpgradeableLoader | | | | |
##### Transfer: Ethereum (native) -> Solana (wrapped) ##### Transfer: Ethereum (native) -> Solana (wrapped)
| Index | Name | Type | signer | writeable | empty | derived | | Index | Name | Type | signer | writeable | empty | derived |

View File

@ -9,58 +9,70 @@ import "google/api/annotations.proto";
// NodePrivileged exposes an administrative API. It runs on a UNIX socket and is authenticated // NodePrivileged exposes an administrative API. It runs on a UNIX socket and is authenticated
// using Linux filesystem permissions. // using Linux filesystem permissions.
service NodePrivileged { service NodePrivileged {
// SubmitGuardianSetVAA injects a guardian set change VAA into the guardian node. // InjectGovernanceVAA injects a governance VAA into the guardian node.
// The node will inject the VAA into the aggregator and sign/broadcast the VAA signature. // The node will inject the VAA into the aggregator and sign/broadcast the VAA signature.
// //
// A consensus majority of nodes on the network will have to inject the VAA within the // A consensus majority of nodes on the network will have to inject the VAA within the
// VAA timeout window for it to reach consensus. // VAA timeout window for it to reach consensus.
// //
rpc SubmitGuardianSetVAA (SubmitGuardianSetVAARequest) returns (SubmitGuardianSetVAAResponse); rpc InjectGovernanceVAA (InjectGovernanceVAARequest) returns (InjectGovernanceVAAResponse);
}
message InjectGovernanceVAARequest {
// Index of the current guardian set.
uint32 current_set_index = 1;
// UNIX timestamp (s) of the VAA to be created. The timestamp is informational and will be part
// of the VAA submitted to the chain. It's part of the VAA digest and has to be identical across nodes and
// is critical for replay protection - a given event may only ever be observed with the same timestamp,
// otherwise, it may be possible to execute it multiple times.
//
// For lockups, the timestamp identifies the block that the lockup belongs to.
// For governance VAAs, guardians inject the VAA manually. Best practice is to pick a timestamp which roughly matches
// the timing of the off-chain ceremony used to achieve consensus. For guardian set updates, the actual on-chain
// guardian set creation timestamp will be set when the VAA is accepted on each chain.
//
// This is a uint32 to match the on-chain timestamp representation. This becomes a problem in 2106 (sorry).
uint32 timestamp = 2;
oneof payload{
GuardianSetUpdate guardian_set = 3;
ContractUpgrade contract_upgrade = 4;
}
}
message InjectGovernanceVAAResponse {
// Canonical digest of the submitted VAA.
bytes digest = 1;
} }
// GuardianSet represents a new guardian set to be submitted to and signed by the node. // GuardianSet represents a new guardian set to be submitted to and signed by the node.
// During the genesis procedure, this data structure will be assembled using off-chain collaborative tooling // During the genesis procedure, this data structure will be assembled using off-chain collaborative tooling
// like GitHub using a human-readable encoding, so readability is a concern. // like GitHub using a human-readable encoding, so readability is a concern.
message GuardianSetUpdate { message GuardianSetUpdate {
// Index of the current guardian set to be replaced. // List of guardian set members.
uint32 current_set_index = 1; message Guardian {
// Guardian key pubkey. Stored as hex string with 0x prefix for human readability -
// UNIX timestamp (s) of the VAA to be created. The timestamp is informational and will be part // this is the canonical Ethereum representation.
// of the VAA submitted to the chain. It's part of the VAA digest and has to be identical across nodes and string pubkey = 1;
// is critical for replay protection - a given event may only ever be observed with the same timestamp, // Optional descriptive name. Not stored on any chain, purely informational.
// otherwise, it may be possible to execute it multiple times. string name = 2;
// };
// For lockups, the timestamp identifies the block that the lockup belongs to. For guardian set updates, repeated Guardian guardians = 3;
// we create the VAA manually. Best practice is to pick a timestamp which roughly matches the expected
// genesis ceremony data.
//
// The actual on-chain guardian set creation timestamp will be set when the VAA is accepted on each chain.
//
// This is a uint32 to match the on-chain timestamp representation. This becomes a problem in 2106 (sorry).
uint32 timestamp = 2;
// List of guardian set members.
message Guardian {
// Guardian key pubkey. Stored as hex string with 0x prefix for human readability -
// this is the canonical Ethereum representation.
string pubkey = 1;
// Optional descriptive name. Not stored on any chain, purely informational.
string name = 2;
};
repeated Guardian guardians = 3;
}
message SubmitGuardianSetVAARequest {
GuardianSetUpdate guardian_set = 1;
}
message SubmitGuardianSetVAAResponse {
// Canonical digest of the submitted VAA.
bytes digest = 1;
} }
// GuardianKey specifies the on-disk format for a node's guardian key. // GuardianKey specifies the on-disk format for a node's guardian key.
message GuardianKey { message GuardianKey {
// data is the binary representation of the secp256k1 private key. // data is the binary representation of the secp256k1 private key.
bytes data = 1; bytes data = 1;
}
// ContractUpgrade represents a Wormhole contract update to be submitted to and signed by the node.
message ContractUpgrade {
// ID of the chain where the Wormhole contract should be updated (uint8).
uint32 chain_id = 1;
// Address of the new program/contract.
bytes new_contract = 2;
} }

View File

@ -9,10 +9,10 @@ path=/tmp/new-guardianset.prototxt
sock=/tmp/admin.sock sock=/tmp/admin.sock
# Create a no-op update that sets the same 1-node guardian set again. # Create a no-op update that sets the same 1-node guardian set again.
kubectl exec guardian-${node} -c guardiand -- /guardiand admin guardian-set-update-template --num=1 --idx=${idx} $path kubectl exec -n wormhole guardian-${node} -c guardiand -- /guardiand template guardian-set-update --num=1 --idx=${idx} $path
# Verify and print resulting result. The digest incorporates the current time and is NOT deterministic. # Verify and print resulting result. The digest incorporates the current time and is NOT deterministic.
kubectl exec guardian-${node} -c guardiand -- /guardiand admin guardian-set-update-verify $path kubectl exec -n wormhole guardian-${node} -c guardiand -- /guardiand admin governance-vaa-verify $path
# Submit to node # Submit to node
kubectl exec guardian-${node} -c guardiand -- /guardiand admin guardian-set-update-inject --socket $sock $path kubectl exec -n wormhole guardian-${node} -c guardiand -- /guardiand admin governance-vaa-inject --socket $sock $path

257
solana/Cargo.lock generated
View File

@ -330,6 +330,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
[[package]]
name = "bytes"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16"
[[package]] [[package]]
name = "bzip2" name = "bzip2"
version = "0.3.3" version = "0.3.3"
@ -823,9 +829,9 @@ dependencies = [
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.7.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e"
dependencies = [ dependencies = [
"atty", "atty",
"humantime", "humantime",
@ -1245,12 +1251,9 @@ checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
[[package]] [[package]]
name = "humantime" name = "humantime"
version = "1.3.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
dependencies = [
"quick-error",
]
[[package]] [[package]]
name = "hyper" name = "hyper"
@ -1563,13 +1566,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]] [[package]]
name = "memmap" name = "memmap2"
version = "0.7.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a"
dependencies = [ dependencies = [
"libc", "libc",
"winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1629,12 +1631,25 @@ dependencies = [
"kernel32-sys", "kernel32-sys",
"libc", "libc",
"log", "log",
"miow", "miow 0.2.2",
"net2", "net2",
"slab", "slab",
"winapi 0.2.8", "winapi 0.2.8",
] ]
[[package]]
name = "mio"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
dependencies = [
"libc",
"log",
"miow 0.3.6",
"ntapi",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "mio-uds" name = "mio-uds"
version = "0.6.8" version = "0.6.8"
@ -1643,7 +1658,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [ dependencies = [
"iovec", "iovec",
"libc", "libc",
"mio", "mio 0.6.23",
] ]
[[package]] [[package]]
@ -1658,6 +1673,16 @@ dependencies = [
"ws2_32-sys", "ws2_32-sys",
] ]
[[package]]
name = "miow"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
"socket2",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "multimap" name = "multimap"
version = "0.8.2" version = "0.8.2"
@ -1684,9 +1709,9 @@ dependencies = [
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.36" version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cf75f38f16cb05ea017784dc6dbfd354f76c223dba37701734c4f5a9337d02" checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"libc", "libc",
@ -1695,15 +1720,23 @@ dependencies = [
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.17.0" version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cc", "cc",
"cfg-if 0.1.10", "cfg-if 1.0.0",
"libc", "libc",
"void", ]
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
"winapi 0.3.9",
] ]
[[package]] [[package]]
@ -2179,12 +2212,6 @@ dependencies = [
"prost", "prost",
] ]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.6.13" version = "0.6.13"
@ -2653,6 +2680,15 @@ dependencies = [
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "signature" name = "signature"
version = "1.2.2" version = "1.2.2"
@ -2694,9 +2730,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-account-decoder" name = "solana-account-decoder"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29fa579ccae25e66c5b9f3e058b16b19efc823e653ee491bbcda1f06a440de7a" checksum = "469a64e65f2788c0fcd68124fce6a490c139a37ee159d855fe45bde9404be96e"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"base64 0.12.3", "base64 0.12.3",
@ -2718,9 +2754,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-clap-utils" name = "solana-clap-utils"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e908b0267c02e3898fb5769109dddbc936f14aadcedd3d5925d1a4d9b120f9" checksum = "5bc41382ae2e834acce6b26e361e0ba79acec3b6633e36189e1cbcd16e3d9edf"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2734,9 +2770,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-cli-config" name = "solana-cli-config"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0f69ef61a624038c6c2e0109f08c827633a04a4d21272e1e02e3bd70961008" checksum = "ef627ff85612a66af08384dfbe006948c74143cee6a0b80311a94e5e0ffe8c2b"
dependencies = [ dependencies = [
"dirs-next", "dirs-next",
"lazy_static", "lazy_static",
@ -2748,9 +2784,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-client" name = "solana-client"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ee3b369812df3c30c9076ac2d5f042e09d7cb9c04e2928ebf5df26ad4ab2" checksum = "3fbe10a0b09201e4d272848644720d75d237dfe92536701b973ecb6a042d8363"
dependencies = [ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"bincode", "bincode",
@ -2759,6 +2795,7 @@ dependencies = [
"indicatif", "indicatif",
"jsonrpc-core", "jsonrpc-core",
"log", "log",
"net2",
"rayon", "rayon",
"reqwest", "reqwest",
"semver 0.11.0", "semver 0.11.0",
@ -2779,9 +2816,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-config-program" name = "solana-config-program"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5c599f4049337d8c89c08811b3044203d083038e4e4be724843088211f3158" checksum = "d0dbb6f55cfd7eefb7d739c3a5b8ff2bba53825f002b7a3fc0531c2a335092a5"
dependencies = [ dependencies = [
"bincode", "bincode",
"chrono", "chrono",
@ -2793,9 +2830,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-crate-features" name = "solana-crate-features"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc73ada8cddc62edf58dc09ef3cf4551259d0ca1c7ece5f102757279ec2afa95" checksum = "a694ee719e16262801bdaeacda065e21352b7607cd7327b180172adca99864dc"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes 0.4.12", "bytes 0.4.12",
@ -2817,13 +2854,12 @@ dependencies = [
[[package]] [[package]]
name = "solana-faucet" name = "solana-faucet"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16cae7630ea7accaae2e6f538f400bcac312271cf4ab882a92875570447650b0" checksum = "ca85d93e05c4270f15c4ce929895bafa42a6d6f368d6d70ada93fbd51add69f8"
dependencies = [ dependencies = [
"bincode", "bincode",
"byteorder", "byteorder",
"bytes 0.4.12",
"clap", "clap",
"log", "log",
"serde", "serde",
@ -2834,21 +2870,20 @@ dependencies = [
"solana-metrics", "solana-metrics",
"solana-sdk", "solana-sdk",
"solana-version", "solana-version",
"tokio 0.1.22", "tokio 0.3.6",
"tokio-codec",
] ]
[[package]] [[package]]
name = "solana-frozen-abi" name = "solana-frozen-abi"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5ab6ad3dda6a3d95d19603eeedc65689d8125eafb3e23c6a1e01ab8a6ba60c" checksum = "2cc29ffc04200709ae0ece6a6a4a78d97043537e0cf70fa36a0cec200140e893"
dependencies = [ dependencies = [
"bs58", "bs58",
"bv", "bv",
"generic-array 0.14.4", "generic-array 0.14.4",
"log", "log",
"memmap", "memmap2",
"rustc_version", "rustc_version",
"serde", "serde",
"serde_derive", "serde_derive",
@ -2860,9 +2895,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-frozen-abi-macro" name = "solana-frozen-abi-macro"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffaa09aa938a67501479ed8a785071c6993f72c34e43f680db3ea7a2dadad9e7" checksum = "9351c5355512afadaa64225d0653b050c768a7d5938429bff8a2e7c17143429f"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"proc-macro2 1.0.24", "proc-macro2 1.0.24",
@ -2873,9 +2908,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-logger" name = "solana-logger"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d949157d0b23eaf5758b427d90741d2a90751c4e3dfee028f5726ab8b36e769" checksum = "188a6e6d7e001336d00ece746ecbd4b5e5ff1a12397c456934d831288f99b23d"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"lazy_static", "lazy_static",
@ -2884,9 +2919,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-measure" name = "solana-measure"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76c197e92932f6498371df4a52e972403b0a3dfd3eac101b2844774b43292d89" checksum = "cef4e2d6ffd08f35e6268b1bcffe63b37a6f9a53d91644757d607b8d3ba4251e"
dependencies = [ dependencies = [
"jemalloc-ctl", "jemalloc-ctl",
"jemallocator", "jemallocator",
@ -2897,9 +2932,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-metrics" name = "solana-metrics"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed2f570bd9d87a991c58800bd94149c34243f14c6b3dfc39fbca602e13db70a" checksum = "4c02403e4f6fcb97e149854c42a0a7e81af041e5228544ad375cd75fb82a859d"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"gethostname", "gethostname",
@ -2911,12 +2946,11 @@ dependencies = [
[[package]] [[package]]
name = "solana-net-utils" name = "solana-net-utils"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea0a40ca7c0f5be26d1a203ac1ef44920f7c845ffdcf922e2aa597662e13958" checksum = "5468c5a5590aef624a668d264cb64f009d0d81ad8c7d609a57dbcb4328fcb2ef"
dependencies = [ dependencies = [
"bincode", "bincode",
"bytes 0.4.12",
"clap", "clap",
"log", "log",
"nix", "nix",
@ -2927,15 +2961,15 @@ dependencies = [
"solana-clap-utils", "solana-clap-utils",
"solana-logger", "solana-logger",
"solana-version", "solana-version",
"tokio 0.1.22", "tokio 0.3.6",
"url", "url",
] ]
[[package]] [[package]]
name = "solana-program" name = "solana-program"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9c6cb16e8aa986bc0d2af8ec50628f7451bef9dac89924adf48302bd4fc755" checksum = "6c16bdd751d5549716a610f87b8ab1ca13ceaf66dfc9f325440894a72eadb74e"
dependencies = [ dependencies = [
"bincode", "bincode",
"bs58", "bs58",
@ -2963,9 +2997,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-rayon-threadlimit" name = "solana-rayon-threadlimit"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de7367bfa559a08c2023d62f780ae01fddf865b974d7fd449bbeb1399641764d" checksum = "72de795cac4d5e9c9c083177bfcbe343c461c1ce5dcffbecddd2d0b7f09e04fa"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"num_cpus", "num_cpus",
@ -2973,9 +3007,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-remote-wallet" name = "solana-remote-wallet"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fde6cc84dfcc15c34eedba0675ca51cbaa8b83ca70233c5751459af869568e1" checksum = "46f7717eca656d386dd233c60d6c63c3d5e16fa64dd3bca1a7f1b27007cf354e"
dependencies = [ dependencies = [
"base32", "base32",
"console 0.11.3", "console 0.11.3",
@ -2993,9 +3027,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-runtime" name = "solana-runtime"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d1364382b1ea6dd516c53455c817eaa5cd47bf7565cd00953586002731dd8fd" checksum = "b817d921c53245e3fcc78ac605fb61ae0ada81346fda7dec41a7681770610ca5"
dependencies = [ dependencies = [
"bincode", "bincode",
"blake3", "blake3",
@ -3013,7 +3047,7 @@ dependencies = [
"libc", "libc",
"libloading", "libloading",
"log", "log",
"memmap", "memmap2",
"num-derive 0.3.3", "num-derive 0.3.3",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
@ -3044,9 +3078,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-sdk" name = "solana-sdk"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c38a02d501422070cd6a4d561b4ab1408e311c5a0b5af3a7bb01246da14f66" checksum = "280fa9cef4fdb9154fea538ed1efdc74215b3734a4ad611ddb1393269efac1bb"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"bincode", "bincode",
@ -3063,7 +3097,7 @@ dependencies = [
"lazy_static", "lazy_static",
"libsecp256k1", "libsecp256k1",
"log", "log",
"memmap", "memmap2",
"num-derive 0.3.3", "num-derive 0.3.3",
"num-traits", "num-traits",
"pbkdf2", "pbkdf2",
@ -3088,9 +3122,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-sdk-macro" name = "solana-sdk-macro"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475a680cd175f2e256452e007c6f8622d3a1ab97ab36d26303b35576e24f340c" checksum = "11489c157e78f60ad9d4a96dc4d1955ef6936ef606f6ce0273689fcdb90391c2"
dependencies = [ dependencies = [
"bs58", "bs58",
"proc-macro2 1.0.24", "proc-macro2 1.0.24",
@ -3101,9 +3135,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-secp256k1-program" name = "solana-secp256k1-program"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f76265997062d8cb18b8055ab200294087ee0bb2de3cf65864eb964f39b2c8" checksum = "3eb1617ea1dec65e59ab94eb6bdcf15e831270ae41317f4e9bee926693f74f30"
dependencies = [ dependencies = [
"bincode", "bincode",
"digest 0.9.0", "digest 0.9.0",
@ -3116,9 +3150,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-stake-program" name = "solana-stake-program"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fcb16ef12c9ed669308074bcc0549d5b36f29597fb701530f108088d438b3cd" checksum = "a691ac55bb8cb4ded6c192ab117b545e3090e92c13560b02318b02ed423eaef6"
dependencies = [ dependencies = [
"bincode", "bincode",
"log", "log",
@ -3138,9 +3172,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-transaction-status" name = "solana-transaction-status"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f69cb54e6854d4799529c22c21c1d53abaf2ebfc7b2c2fe1ce84b2afb9c620" checksum = "ede0f19e5bec9b0d9a85c4eba2f453547064b124b4849ddfe6e7212a94aa75b0"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"base64 0.12.3", "base64 0.12.3",
@ -3162,9 +3196,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-version" name = "solana-version"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6995a2a6734a108b4a80497a391e86c8d234d94b02ceec0cebc9ba132874502" checksum = "94bc42af0fb331572e8161e099f4b1c50cec8f12c3d64d61ff04c0719199aebb"
dependencies = [ dependencies = [
"log", "log",
"rustc_version", "rustc_version",
@ -3178,9 +3212,9 @@ dependencies = [
[[package]] [[package]]
name = "solana-vote-program" name = "solana-vote-program"
version = "1.4.14" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b42b3fd7b76dd8c98eb13f92677b1803d0bc1ac06af45e10f1aee46b8c19a8a" checksum = "c9a3c8a54916bb189a80dee075bae93950198ac8b51cde6d2e7e8860b8a05250"
dependencies = [ dependencies = [
"bincode", "bincode",
"log", "log",
@ -3205,18 +3239,18 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "spl-memo" name = "spl-memo"
version = "2.0.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99775feb54f735a6826ea0af500c1f78f7a5974d6b17f1ac586cd114e2da7d80" checksum = "fb2b771f6146dec14ef5fbf498f9374652c54badc3befc8c40c1d426dd45d720"
dependencies = [ dependencies = [
"solana-program", "solana-program",
] ]
[[package]] [[package]]
name = "spl-token" name = "spl-token"
version = "3.0.0" version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f77fa0b41cbc82d1d7c8f2d914b49e9a1a7b6e32af952d03383fb989c42bc89" checksum = "a9774eebb62ff1ff2f5eca112413e476143925a2f5a43cee98fc5d3a6c0eec5c"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"num-derive 0.3.3", "num-derive 0.3.3",
@ -3447,7 +3481,7 @@ checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
dependencies = [ dependencies = [
"bytes 0.4.12", "bytes 0.4.12",
"futures 0.1.30", "futures 0.1.30",
"mio", "mio 0.6.23",
"num_cpus", "num_cpus",
"tokio-codec", "tokio-codec",
"tokio-current-thread", "tokio-current-thread",
@ -3476,12 +3510,34 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"memchr", "memchr",
"mio", "mio 0.6.23",
"mio-uds", "mio-uds",
"num_cpus", "num_cpus",
"pin-project-lite 0.1.11", "pin-project-lite 0.1.11",
"slab", "slab",
"tokio-macros", "tokio-macros 0.2.6",
]
[[package]]
name = "tokio"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "720ba21c25078711bf456d607987d95bce90f7c3bea5abe1db587862e7a1e87c"
dependencies = [
"autocfg",
"bytes 0.6.0",
"futures-core",
"libc",
"memchr",
"mio 0.7.7",
"num_cpus",
"once_cell",
"parking_lot 0.11.1",
"pin-project-lite 0.2.0",
"signal-hook-registry",
"slab",
"tokio-macros 0.3.2",
"winapi 0.3.9",
] ]
[[package]] [[package]]
@ -3548,6 +3604,17 @@ dependencies = [
"syn 1.0.53", "syn 1.0.53",
] ]
[[package]]
name = "tokio-macros"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46dfffa59fc3c8aad216ed61bdc2c263d2b9d87a9c8ac9de0c11a813e51b6db7"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.53",
]
[[package]] [[package]]
name = "tokio-reactor" name = "tokio-reactor"
version = "0.1.12" version = "0.1.12"
@ -3558,7 +3625,7 @@ dependencies = [
"futures 0.1.30", "futures 0.1.30",
"lazy_static", "lazy_static",
"log", "log",
"mio", "mio 0.6.23",
"num_cpus", "num_cpus",
"parking_lot 0.9.0", "parking_lot 0.9.0",
"slab", "slab",
@ -3598,7 +3665,7 @@ dependencies = [
"bytes 0.4.12", "bytes 0.4.12",
"futures 0.1.30", "futures 0.1.30",
"iovec", "iovec",
"mio", "mio 0.6.23",
"tokio-io", "tokio-io",
"tokio-reactor", "tokio-reactor",
] ]
@ -3641,7 +3708,7 @@ dependencies = [
"bytes 0.4.12", "bytes 0.4.12",
"futures 0.1.30", "futures 0.1.30",
"log", "log",
"mio", "mio 0.6.23",
"tokio-codec", "tokio-codec",
"tokio-io", "tokio-io",
"tokio-reactor", "tokio-reactor",
@ -3658,7 +3725,7 @@ dependencies = [
"iovec", "iovec",
"libc", "libc",
"log", "log",
"mio", "mio 0.6.23",
"mio-uds", "mio-uds",
"tokio-codec", "tokio-codec",
"tokio-io", "tokio-io",
@ -4114,12 +4181,6 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.1" version = "2.3.1"

View File

@ -9,10 +9,10 @@ tonic = "0.3.0"
tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds"] } tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds"] }
prost = "0.6" prost = "0.6"
prost-types = "0.6" prost-types = "0.6"
solana-sdk = { version = "1.4.7" } solana-sdk = { version = "1.4.20" }
solana-client = { version = "1.4.7" } solana-client = { version = "1.4.20" }
solana-faucet = "1.4.7" solana-faucet = "1.4.20"
spl-token = "=3.0.0" spl-token = "=3.0.1"
wormhole-bridge = { path = "../bridge" } wormhole-bridge = { path = "../bridge" }
primitive-types = { version = "0.7.2" } primitive-types = { version = "0.7.2" }
hex = "0.4.2" hex = "0.4.2"
@ -21,7 +21,7 @@ tungstenite = "0.11.1"
serde = "1.0.103" serde = "1.0.103"
url = "2.1.1" url = "2.1.1"
serde_bytes = "0.11.5" serde_bytes = "0.11.5"
log = "0.4.8" log = "0.4.11"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.57" serde_json = "1.0.57"
bs58 = "0.3.1" bs58 = "0.3.1"

View File

@ -17,8 +17,8 @@ program = ["spl-token/no-entrypoint"]
num-derive = "0.2" num-derive = "0.2"
num-traits = "0.2" num-traits = "0.2"
remove_dir_all = "=0.5.0" remove_dir_all = "=0.5.0"
solana-program = "1.4.7" solana-program = "1.4.20"
spl-token = { version = "=3.0.0" } spl-token = { version = "=3.0.1" }
thiserror = "1.0" thiserror = "1.0"
byteorder = "1.3.4" byteorder = "1.3.4"
zerocopy = "0.3.0" zerocopy = "0.3.0"

View File

@ -112,6 +112,9 @@ pub enum Error {
/// Invalid Sysvar /// Invalid Sysvar
#[error("InvalidSysvar")] #[error("InvalidSysvar")]
InvalidSysvar, InvalidSysvar,
/// Invalid Chain
#[error("InvalidChain")]
InvalidChain,
} }
impl From<Error> for ProgramError { impl From<Error> for ProgramError {

View File

@ -42,6 +42,7 @@ impl PrintProgramError for Error {
Error::InsufficientFees => msg!("Error: InsufficientFees"), Error::InsufficientFees => msg!("Error: InsufficientFees"),
Error::InvalidOwner => msg!("Error: InvalidOwner"), Error::InvalidOwner => msg!("Error: InvalidOwner"),
Error::InvalidSysvar => msg!("Error: InvalidSysvar"), Error::InvalidSysvar => msg!("Error: InvalidSysvar"),
Error::InvalidChain => msg!("Error: InvalidChain"),
} }
} }
} }

View File

@ -425,6 +425,12 @@ pub fn post_vaa(
Bridge::derive_guardian_set_id(program_id, &bridge_key, u.new_index)?; Bridge::derive_guardian_set_id(program_id, &bridge_key, u.new_index)?;
accounts.push(AccountMeta::new(guardian_set_key, false)); accounts.push(AccountMeta::new(guardian_set_key, false));
} }
VAABody::UpgradeContract(u) => {
accounts.push(AccountMeta::new(u.buffer, false));
let (programdata_address, _) = Pubkey::find_program_address(&[program_id.as_ref()], &solana_program::bpf_loader_upgradeable::id());
accounts.push(AccountMeta::new(programdata_address, false));
accounts.push(AccountMeta::new_readonly(solana_program::bpf_loader_upgradeable::id(), false));
}
VAABody::Transfer(t) => { VAABody::Transfer(t) => {
if t.source_chain == CHAIN_ID_SOLANA { if t.source_chain == CHAIN_ID_SOLANA {
// Solana (any) -> Ethereum (any) // Solana (any) -> Ethereum (any)

View File

@ -36,6 +36,7 @@ use solana_program::program_pack::Pack;
use std::borrow::BorrowMut; use std::borrow::BorrowMut;
use std::ops::Add; use std::ops::Add;
use solana_program::fee_calculator::FeeCalculator; use solana_program::fee_calculator::FeeCalculator;
use crate::vaa::BodyContractUpgrade;
/// SigInfo contains metadata about signers in a VerifySignature ix /// SigInfo contains metadata about signers in a VerifySignature ix
struct SigInfo { struct SigInfo {
@ -772,6 +773,19 @@ impl Bridge {
) )
} }
} }
VAABody::UpgradeContract(v) => {
if v.chain_id == CHAIN_ID_SOLANA {
evict_signatures = true;
Self::process_vaa_upgrade(
program_id,
accounts,
bridge_info,
v,
)
} else {
return Err(Error::InvalidChain.into());
}
}
}?; }?;
// Check and create claim // Check and create claim
@ -1001,6 +1015,25 @@ impl Bridge {
Ok(()) Ok(())
} }
/// Processes a VAA contract upgrade
pub fn process_vaa_upgrade(
program_id: &Pubkey,
accounts: &[AccountInfo],
bridge_info: &AccountInfo,
b: &BodyContractUpgrade,
) -> ProgramResult {
// Invoke upgrade
let upgrade_ix = solana_program::bpf_loader_upgradeable::upgrade(
program_id,
&b.buffer,
bridge_info.key,
bridge_info.key,
);
Self::invoke_as_bridge(program_id, &upgrade_ix, accounts);
Ok(())
}
/// Creates a new wrapped asset /// Creates a new wrapped asset
pub fn process_create_wrapped( pub fn process_create_wrapped(
program_id: &Pubkey, program_id: &Pubkey,

View File

@ -6,6 +6,7 @@ use sha3::Digest;
use solana_program::program_error::ProgramError; use solana_program::program_error::ProgramError;
use crate::{error::Error, state::AssetMeta}; use crate::{error::Error, state::AssetMeta};
use solana_program::pubkey::Pubkey;
pub type ForeignAddress = [u8; 32]; pub type ForeignAddress = [u8; 32];
@ -129,12 +130,14 @@ impl VAA {
pub enum VAABody { pub enum VAABody {
UpdateGuardianSet(BodyUpdateGuardianSet), UpdateGuardianSet(BodyUpdateGuardianSet),
Transfer(BodyTransfer), Transfer(BodyTransfer),
UpgradeContract(BodyContractUpgrade),
} }
impl VAABody { impl VAABody {
fn action_id(&self) -> u8 { fn action_id(&self) -> u8 {
match self { match self {
VAABody::UpdateGuardianSet(_) => 0x01, VAABody::UpdateGuardianSet(_) => 0x01,
VAABody::UpgradeContract(_) => 0x02,
VAABody::Transfer(_) => 0x10, VAABody::Transfer(_) => 0x10,
} }
} }
@ -147,6 +150,7 @@ impl VAABody {
0x01 => { 0x01 => {
VAABody::UpdateGuardianSet(BodyUpdateGuardianSet::deserialize(&mut payload_data)?) VAABody::UpdateGuardianSet(BodyUpdateGuardianSet::deserialize(&mut payload_data)?)
} }
0x02 => VAABody::UpgradeContract(BodyContractUpgrade::deserialize(&mut payload_data)?),
0x10 => VAABody::Transfer(BodyTransfer::deserialize(&mut payload_data)?), 0x10 => VAABody::Transfer(BodyTransfer::deserialize(&mut payload_data)?),
_ => { _ => {
return Err(Error::InvalidVAAAction); return Err(Error::InvalidVAAAction);
@ -160,6 +164,7 @@ impl VAABody {
match self { match self {
VAABody::Transfer(b) => b.serialize(), VAABody::Transfer(b) => b.serialize(),
VAABody::UpdateGuardianSet(b) => b.serialize(), VAABody::UpdateGuardianSet(b) => b.serialize(),
VAABody::UpgradeContract(b) => b.serialize(),
} }
} }
} }
@ -181,6 +186,34 @@ pub struct BodyTransfer {
pub amount: U256, pub amount: U256,
} }
#[derive(Clone, Debug, PartialEq)]
pub struct BodyContractUpgrade {
pub chain_id: u8,
pub buffer: Pubkey,
}
impl BodyContractUpgrade {
fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyContractUpgrade, Error> {
let chain_id = data.read_u8()?;
let mut key: [u8; 32] = [0; 32];
data.read(&mut key[..])?;
Ok(BodyContractUpgrade {
chain_id,
buffer: Pubkey::new(&key[..]),
})
}
fn serialize(&self) -> Result<Vec<u8>, Error> {
let mut v: Cursor<Vec<u8>> = Cursor::new(Vec::new());
v.write_u8(self.chain_id)?;
v.write(&self.buffer.to_bytes());
Ok(v.into_inner())
}
}
impl BodyUpdateGuardianSet { impl BodyUpdateGuardianSet {
fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyUpdateGuardianSet, Error> { fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyUpdateGuardianSet, Error> {
let new_index = data.read_u32::<BigEndian>()?; let new_index = data.read_u32::<BigEndian>()?;
@ -273,6 +306,8 @@ mod tests {
state::AssetMeta, state::AssetMeta,
vaa::{BodyTransfer, BodyUpdateGuardianSet, Signature, VAABody, VAA}, vaa::{BodyTransfer, BodyUpdateGuardianSet, Signature, VAABody, VAA},
}; };
use crate::vaa::BodyContractUpgrade;
use solana_program::pubkey::Pubkey;
#[test] #[test]
fn serialize_deserialize_vaa_transfer() { fn serialize_deserialize_vaa_transfer() {
@ -329,6 +364,29 @@ mod tests {
assert_eq!(vaa, parsed_vaa) assert_eq!(vaa, parsed_vaa)
} }
#[test]
fn serialize_deserialize_vaa_contract_upgrade() {
let vaa = VAA {
version: 8,
guardian_set_index: 3,
signatures: vec![Signature {
index: 1,
r: [2; 32],
s: [2; 32],
v: 7,
}],
timestamp: 83,
payload: Some(VAABody::UpgradeContract(BodyContractUpgrade {
chain_id: 3,
buffer: Pubkey::new_unique(),
})),
};
let data = vaa.serialize().unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa)
}
#[test] #[test]
fn parse_given_guardian_set_update() { fn parse_given_guardian_set_update() {
let vaa = VAA { let vaa = VAA {
@ -411,4 +469,36 @@ mod tests {
let rec_data = parsed_vaa.serialize().unwrap(); let rec_data = parsed_vaa.serialize().unwrap();
assert_eq!(data, rec_data); assert_eq!(data, rec_data);
} }
#[test]
fn parse_given_contract_upgrade() {
let vaa = VAA {
version: 1,
guardian_set_index: 2,
signatures: vec![Signature {
index: 0,
r: [
72, 156, 56, 20, 222, 146, 161, 112, 22, 97, 69, 59, 188, 199, 130, 240, 89,
249, 241, 79, 96, 27, 235, 10, 99, 16, 56, 80, 232, 188, 235, 11
],
s: [
65, 19, 144, 42, 104, 122, 52, 0, 126, 7, 43, 127, 120, 85, 5, 21, 216, 207,
78, 73, 213, 207, 142, 103, 211, 192, 100, 90, 27, 98, 176, 98
],
v: 1,
}],
timestamp: 4000,
payload: Some(VAABody::UpgradeContract(BodyContractUpgrade {
chain_id: 2,
buffer: Pubkey::new(&[146, 115, 122, 21, 4, 243, 179, 223, 140, 147, 203, 133, 198, 74, 72, 96, 187,
39, 14, 38, 2, 107, 110, 55, 240, 149, 53, 106, 64, 111, 106, 244]),
})),
};
let data = hex::decode("01000000020100489c3814de92a1701661453bbcc782f059f9f14f601beb0a63103850e8bceb0b4113902a687a34007e072b7f78550515d8cf4e49d5cf8e67d3c0645a1b62b0620100000fa0020292737a1504f3b3df8c93cb85c64a4860bb270e26026b6e37f095356a406f6af4").unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa);
let rec_data = parsed_vaa.serialize().unwrap();
assert_eq!(data, rec_data);
}
} }

View File

@ -8,14 +8,14 @@ edition = "2018"
[dependencies] [dependencies]
clap = "2.33.0" clap = "2.33.0"
solana-clap-utils = { version = "1.4.7" } solana-clap-utils = { version = "1.4.20" }
solana-cli-config = { version = "1.4.7" } solana-cli-config = { version = "1.4.20" }
solana-logger = { version = "1.4.7" } solana-logger = { version = "1.4.20" }
solana-sdk = { version = "1.4.7" } solana-sdk = { version = "1.4.20" }
solana-client = { version = "1.4.7" } solana-client = { version = "1.4.20" }
solana-faucet = "1.4.7" solana-faucet = "1.4.20"
solana-account-decoder = { version = "1.4.7" } solana-account-decoder = { version = "1.4.20" }
spl-token = "=3.0.0" spl-token = "=3.0.1"
wormhole-bridge = { path = "../bridge" } wormhole-bridge = { path = "../bridge" }
primitive-types = { version = "0.7.2" } primitive-types = { version = "0.7.2" }
hex = "0.4.2" hex = "0.4.2"

View File

@ -11,7 +11,7 @@ RUN rustup component add rustfmt
WORKDIR /usr/src/solana WORKDIR /usr/src/solana
RUN git clone https://github.com/solana-labs/solana --branch master && \ RUN git clone https://github.com/solana-labs/solana --branch master && \
cd solana && git checkout v1.4.12 cd solana && git checkout v1.4.20
ADD *.patch . ADD *.patch .