solana-go/programs/system/instructions.go

236 lines
6.7 KiB
Go
Raw Normal View History

2020-11-09 10:09:50 -08:00
// Copyright 2020 dfuse Platform Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package system
import (
2020-11-24 11:39:33 -08:00
"bytes"
2020-11-26 09:51:11 -08:00
"encoding/binary"
"fmt"
2021-08-09 06:44:34 -07:00
"github.com/davecgh/go-spew/spew"
bin "github.com/dfuse-io/binary"
solana "github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/text"
2021-08-09 06:44:34 -07:00
"github.com/gagliardetto/treeout"
)
2021-08-11 09:21:35 -07:00
var (
ProgramID = solana.MustPublicKeyFromBase58("11111111111111111111111111111111")
)
const ProgramName = "System"
func init() {
2021-08-11 09:21:35 -07:00
solana.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction)
}
2021-07-29 08:19:13 -07:00
const (
// Create a new account.
Instruction_CreateAccount uint32 = iota
2021-07-29 08:19:13 -07:00
// Assign account to a program.
Instruction_Assign
2021-07-29 08:19:13 -07:00
// Transfer lamports.
Instruction_Transfer
2021-07-29 08:19:13 -07:00
// Create a new account at an address derived from a base pubkey and a seed.
Instruction_CreateAccountWithSeed
2021-07-29 08:19:13 -07:00
// Consumes a stored nonce, replacing it with a successor.
Instruction_AdvanceNonceAccount
2020-11-26 14:05:05 -08:00
2021-07-29 08:19:13 -07:00
// Withdraw funds from a nonce account.
Instruction_WithdrawNonceAccount
// Drive state of Uninitalized nonce account to Initialized, setting the nonce value.
Instruction_InitializeNonceAccount
2021-07-29 10:36:32 -07:00
// Change the entity authorized to execute nonce instructions on the account.
2021-07-29 08:19:13 -07:00
Instruction_AuthorizeNonceAccount
// Allocate space in a (possibly new) account without funding.
Instruction_Allocate
// Allocate space for and assign an account at an address derived from a base public key and a seed.
Instruction_AllocateWithSeed
// Assign account to a program based on a seed.
Instruction_AssignWithSeed
// Transfer lamports from a derived address.
Instruction_TransferWithSeed
)
2021-07-27 12:10:13 -07:00
2021-08-11 09:21:35 -07:00
func InstructionIDToName(id uint32) string {
switch id {
case Instruction_CreateAccount:
return "CreateAccount"
case Instruction_Assign:
return "Assign"
case Instruction_Transfer:
return "Transfer"
case Instruction_CreateAccountWithSeed:
return "CreateAccountWithSeed"
case Instruction_AdvanceNonceAccount:
return "AdvanceNonceAccount"
case Instruction_WithdrawNonceAccount:
return "WithdrawNonceAccount"
case Instruction_InitializeNonceAccount:
return "InitializeNonceAccount"
case Instruction_AuthorizeNonceAccount:
return "AuthorizeNonceAccount"
case Instruction_Allocate:
return "Allocate"
case Instruction_AllocateWithSeed:
return "AllocateWithSeed"
case Instruction_AssignWithSeed:
return "AssignWithSeed"
case Instruction_TransferWithSeed:
return "TransferWithSeed"
default:
return ""
}
}
type Instruction struct {
bin.BaseVariant
}
2021-08-21 08:53:13 -07:00
var _ bin.EncoderDecoder = &Instruction{}
2021-07-29 08:19:13 -07:00
var (
// TODO: each instruction must be here:
_ solana.AccountsGettable = &CreateAccount{}
_ solana.AccountsSettable = &CreateAccount{}
_ solana.AccountsGettable = &Assign{}
_ solana.AccountsSettable = &Assign{}
_ solana.AccountsGettable = &Transfer{}
_ solana.AccountsSettable = &Transfer{}
_ solana.AccountsGettable = &CreateAccountWithSeed{}
_ solana.AccountsSettable = &CreateAccountWithSeed{}
_ solana.AccountsGettable = &AdvanceNonceAccount{}
_ solana.AccountsSettable = &AdvanceNonceAccount{}
2021-07-29 08:58:03 -07:00
_ solana.AccountsGettable = &WithdrawNonceAccount{}
_ solana.AccountsSettable = &WithdrawNonceAccount{}
_ solana.AccountsGettable = &InitializeNonceAccount{}
_ solana.AccountsSettable = &InitializeNonceAccount{}
_ solana.AccountsGettable = &AuthorizeNonceAccount{}
_ solana.AccountsSettable = &AuthorizeNonceAccount{}
_ solana.AccountsGettable = &Allocate{}
_ solana.AccountsSettable = &Allocate{}
_ solana.AccountsGettable = &AllocateWithSeed{}
_ solana.AccountsSettable = &AllocateWithSeed{}
_ solana.AccountsGettable = &AssignWithSeed{}
_ solana.AccountsSettable = &AssignWithSeed{}
_ solana.AccountsGettable = &TransferWithSeed{}
_ solana.AccountsSettable = &TransferWithSeed{}
2021-07-29 08:19:13 -07:00
)
func (ins *Instruction) Accounts() (out []*solana.AccountMeta) {
return ins.Impl.(solana.AccountsGettable).GetAccounts()
2020-11-26 14:05:05 -08:00
}
2021-07-29 08:19:13 -07:00
// InstructionImplDef is used for deciding binary,
// encoding and decoding json.
var InstructionImplDef = bin.NewVariantDefinition(
bin.Uint32TypeIDEncoding,
[]bin.VariantType{
// TODO:
{"create_account", (*CreateAccount)(nil)},
{"assign", (*Assign)(nil)},
{"transfer", (*Transfer)(nil)},
{"create_account_with_seed", (*CreateAccountWithSeed)(nil)},
{"advance_nonce_account", (*AdvanceNonceAccount)(nil)},
2021-07-29 08:58:03 -07:00
{"withdraw_nonce_account", (*WithdrawNonceAccount)(nil)},
{"initialize_nonce_account", (*InitializeNonceAccount)(nil)},
{"authorize_nonce_account", (*AuthorizeNonceAccount)(nil)},
{"allocate", (*Allocate)(nil)},
{"allocate_with_seed", (*AllocateWithSeed)(nil)},
{"assign_with_seed", (*AssignWithSeed)(nil)},
{"transfer_with_seed", (*TransferWithSeed)(nil)},
2021-07-29 08:19:13 -07:00
})
2020-11-26 14:05:05 -08:00
func (i *Instruction) ProgramID() solana.PublicKey {
2021-08-11 09:21:35 -07:00
return ProgramID
2020-11-26 14:05:05 -08:00
}
func (i *Instruction) Data() ([]byte, error) {
buf := new(bytes.Buffer)
2021-08-21 08:53:13 -07:00
if err := bin.NewBinEncoder(buf).Encode(i); err != nil {
2020-11-26 14:05:05 -08:00
return nil, fmt.Errorf("unable to encode instruction: %w", err)
}
return buf.Bytes(), nil
}
func (i *Instruction) TextEncode(encoder *text.Encoder, option *text.Option) error {
return encoder.Encode(i.Impl, option)
}
2021-08-21 08:53:13 -07:00
func (i *Instruction) UnmarshalWithDecoder(decoder *bin.Decoder) error {
return i.BaseVariant.UnmarshalBinaryVariant(decoder, InstructionImplDef)
}
2021-08-21 08:53:13 -07:00
func (i *Instruction) MarshalWithEncoder(encoder *bin.Encoder) error {
2020-11-26 09:51:11 -08:00
err := encoder.WriteUint32(i.TypeID, binary.LittleEndian)
if err != nil {
return fmt.Errorf("unable to write variant type: %w", err)
}
return encoder.Encode(i.Impl)
}
2021-07-29 08:19:13 -07:00
func registryDecodeInstruction(accounts []*solana.AccountMeta, data []byte) (interface{}, error) {
inst, err := DecodeInstruction(accounts, data)
if err != nil {
return nil, err
}
2021-07-29 08:19:13 -07:00
return inst, nil
}
2021-07-29 08:19:13 -07:00
func DecodeInstruction(accounts []*solana.AccountMeta, data []byte) (*Instruction, error) {
var inst *Instruction
2021-08-21 08:53:13 -07:00
if err := bin.NewBinDecoder(data).Decode(&inst); err != nil {
2021-08-08 08:51:50 -07:00
return nil, fmt.Errorf("unable to decode instruction: %w", err)
}
2021-07-29 08:19:13 -07:00
if v, ok := inst.Impl.(solana.AccountsSettable); ok {
err := v.SetAccounts(accounts)
if err != nil {
return nil, fmt.Errorf("unable to set accounts for instruction: %w", err)
}
}
2021-07-29 08:19:13 -07:00
return inst, nil
}
2021-08-09 06:44:34 -07:00
func (inst *Instruction) EncodeToTree(parent treeout.Branches) {
if enToTree, ok := inst.Impl.(text.EncodableToTree); ok {
enToTree.EncodeToTree(parent)
} else {
parent.Child(spew.Sdump(inst))
}
}