Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 137 additions & 4 deletions programs/vote/Authorize.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,152 @@
package vote

import (
"encoding/binary"
"errors"
"fmt"

bin "github.com/gagliardetto/binary"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/text/format"
"github.com/gagliardetto/treeout"
)

// Authorize is the Authorize instruction.
// Data: (Pubkey, VoteAuthorize)
type Authorize struct {
// TODO
NewAuthority *solana.PublicKey
VoteAuthorize *VoteAuthorizeKind

// [0] = [WRITE] VoteAccount
// ··········· Unitialized vote account
//
// [1] = [] SysVarClock
// ··········· Clock sysvar
//
// [2] = [SIGNER] Authority
// ··········· Vote or withdraw authority
// ··········· Current vote or withdraw authority.
solana.AccountMetaSlice `bin:"-" borsh_skip:"true"`
}

func NewAuthorizeInstructionBuilder() *Authorize {
return &Authorize{
AccountMetaSlice: make(solana.AccountMetaSlice, 3),
}
}

func NewAuthorizeInstruction(
newAuthority solana.PublicKey,
kind VoteAuthorizeKind,
voteAccount solana.PublicKey,
currentAuthority solana.PublicKey,
) *Authorize {
return NewAuthorizeInstructionBuilder().
SetNewAuthority(newAuthority).
SetVoteAuthorize(kind).
SetVoteAccount(voteAccount).
SetClockSysvar(solana.SysVarClockPubkey).
SetAuthority(currentAuthority)
}

func (inst *Authorize) SetNewAuthority(pk solana.PublicKey) *Authorize {
inst.NewAuthority = &pk
return inst
}

func (inst *Authorize) SetVoteAuthorize(kind VoteAuthorizeKind) *Authorize {
inst.VoteAuthorize = &kind
return inst
}

func (inst *Authorize) SetVoteAccount(pk solana.PublicKey) *Authorize {
inst.AccountMetaSlice[0] = solana.Meta(pk).WRITE()
return inst
}

func (inst *Authorize) SetClockSysvar(pk solana.PublicKey) *Authorize {
inst.AccountMetaSlice[1] = solana.Meta(pk)
return inst
}

func (inst *Authorize) SetAuthority(pk solana.PublicKey) *Authorize {
inst.AccountMetaSlice[2] = solana.Meta(pk).SIGNER()
return inst
}

func (inst *Authorize) GetVoteAccount() *solana.AccountMeta { return inst.AccountMetaSlice[0] }
func (inst *Authorize) GetClockSysvar() *solana.AccountMeta { return inst.AccountMetaSlice[1] }
func (inst *Authorize) GetAuthority() *solana.AccountMeta { return inst.AccountMetaSlice[2] }

func (inst Authorize) Build() *Instruction {
return &Instruction{BaseVariant: bin.BaseVariant{
Impl: inst,
TypeID: bin.TypeIDFromUint32(Instruction_Authorize, bin.LE),
}}
}

func (inst Authorize) ValidateAndBuild() (*Instruction, error) {
if err := inst.Validate(); err != nil {
return nil, err
}
return inst.Build(), nil
}

func (inst *Authorize) Validate() error {
if inst.NewAuthority == nil {
return errors.New("NewAuthority parameter is not set")
}
if inst.VoteAuthorize == nil {
return errors.New("VoteAuthorize parameter is not set")
}
for i, acc := range inst.AccountMetaSlice {
if acc == nil {
return fmt.Errorf("accounts[%d] is not set", i)
}
}
return nil
}

func (inst *Authorize) UnmarshalWithDecoder(dec *bin.Decoder) error {
b, err := dec.ReadNBytes(32)
if err != nil {
return err
}
pk := solana.PublicKeyFromBytes(b)
inst.NewAuthority = &pk
raw, err := dec.ReadUint32(binary.LittleEndian)
if err != nil {
return err
}
kind := VoteAuthorizeKind(raw)
inst.VoteAuthorize = &kind
return nil
}

func (inst Authorize) MarshalWithEncoder(enc *bin.Encoder) error {
if inst.NewAuthority == nil {
return errors.New("Authorize.NewAuthority is nil")
}
if inst.VoteAuthorize == nil {
return errors.New("Authorize.VoteAuthorize is nil")
}
if err := enc.WriteBytes(inst.NewAuthority[:], false); err != nil {
return err
}
return enc.WriteUint32(uint32(*inst.VoteAuthorize), binary.LittleEndian)
}

func (inst *Authorize) EncodeToTree(parent treeout.Branches) {
parent.Child(format.Program(ProgramName, ProgramID)).
ParentFunc(func(programBranch treeout.Branches) {
programBranch.Child(format.Instruction("Authorize")).
ParentFunc(func(instructionBranch treeout.Branches) {
instructionBranch.Child("Params").ParentFunc(func(paramsBranch treeout.Branches) {
paramsBranch.Child(format.Param(" NewAuthority", inst.NewAuthority))
paramsBranch.Child(format.Param("VoteAuthorize", inst.VoteAuthorize))
})
instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch treeout.Branches) {
accountsBranch.Child(format.Meta("VoteAccount", inst.AccountMetaSlice[0]))
accountsBranch.Child(format.Meta("ClockSysvar", inst.AccountMetaSlice[1]))
accountsBranch.Child(format.Meta(" Authority", inst.AccountMetaSlice[2]))
})
})
})
}
126 changes: 126 additions & 0 deletions programs/vote/AuthorizeChecked.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package vote

import (
"encoding/binary"
"errors"
"fmt"

bin "github.com/gagliardetto/binary"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/text/format"
"github.com/gagliardetto/treeout"
)

// AuthorizeChecked is the checked variant of Authorize.
// Data: VoteAuthorize (u32 LE, plus BLS fields if kind=2).
type AuthorizeChecked struct {
VoteAuthorize *VoteAuthorizeKind

// [0] = [WRITE] VoteAccount
// [1] = [] SysVarClock
// [2] = [SIGNER] CurrentAuthority
// [3] = [SIGNER] NewAuthority
solana.AccountMetaSlice `bin:"-" borsh_skip:"true"`
}

func NewAuthorizeCheckedInstructionBuilder() *AuthorizeChecked {
return &AuthorizeChecked{
AccountMetaSlice: make(solana.AccountMetaSlice, 4),
}
}

func NewAuthorizeCheckedInstruction(
kind VoteAuthorizeKind,
voteAccount solana.PublicKey,
currentAuthority solana.PublicKey,
newAuthority solana.PublicKey,
) *AuthorizeChecked {
return NewAuthorizeCheckedInstructionBuilder().
SetVoteAuthorize(kind).
SetVoteAccount(voteAccount).
SetClockSysvar(solana.SysVarClockPubkey).
SetCurrentAuthority(currentAuthority).
SetNewAuthority(newAuthority)
}

func (inst *AuthorizeChecked) SetVoteAuthorize(k VoteAuthorizeKind) *AuthorizeChecked {
inst.VoteAuthorize = &k
return inst
}
func (inst *AuthorizeChecked) SetVoteAccount(pk solana.PublicKey) *AuthorizeChecked {
inst.AccountMetaSlice[0] = solana.Meta(pk).WRITE()
return inst
}
func (inst *AuthorizeChecked) SetClockSysvar(pk solana.PublicKey) *AuthorizeChecked {
inst.AccountMetaSlice[1] = solana.Meta(pk)
return inst
}
func (inst *AuthorizeChecked) SetCurrentAuthority(pk solana.PublicKey) *AuthorizeChecked {
inst.AccountMetaSlice[2] = solana.Meta(pk).SIGNER()
return inst
}
func (inst *AuthorizeChecked) SetNewAuthority(pk solana.PublicKey) *AuthorizeChecked {
inst.AccountMetaSlice[3] = solana.Meta(pk).SIGNER()
return inst
}

func (inst AuthorizeChecked) Build() *Instruction {
return &Instruction{BaseVariant: bin.BaseVariant{
Impl: inst,
TypeID: bin.TypeIDFromUint32(Instruction_AuthorizeChecked, bin.LE),
}}
}

func (inst AuthorizeChecked) ValidateAndBuild() (*Instruction, error) {
if err := inst.Validate(); err != nil {
return nil, err
}
return inst.Build(), nil
}

func (inst *AuthorizeChecked) Validate() error {
if inst.VoteAuthorize == nil {
return errors.New("VoteAuthorize parameter is not set")
}
for i, a := range inst.AccountMetaSlice {
if a == nil {
return fmt.Errorf("accounts[%d] is not set", i)
}
}
return nil
}

func (inst *AuthorizeChecked) UnmarshalWithDecoder(dec *bin.Decoder) error {
raw, err := dec.ReadUint32(binary.LittleEndian)
if err != nil {
return err
}
k := VoteAuthorizeKind(raw)
inst.VoteAuthorize = &k
return nil
}

func (inst AuthorizeChecked) MarshalWithEncoder(enc *bin.Encoder) error {
if inst.VoteAuthorize == nil {
return errors.New("AuthorizeChecked.VoteAuthorize is nil")
}
return enc.WriteUint32(uint32(*inst.VoteAuthorize), binary.LittleEndian)
}

func (inst *AuthorizeChecked) EncodeToTree(parent treeout.Branches) {
parent.Child(format.Program(ProgramName, ProgramID)).
ParentFunc(func(programBranch treeout.Branches) {
programBranch.Child(format.Instruction("AuthorizeChecked")).
ParentFunc(func(instructionBranch treeout.Branches) {
instructionBranch.Child("Params").ParentFunc(func(paramsBranch treeout.Branches) {
paramsBranch.Child(format.Param("VoteAuthorize", inst.VoteAuthorize))
})
instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch treeout.Branches) {
accountsBranch.Child(format.Meta(" VoteAccount", inst.AccountMetaSlice[0]))
accountsBranch.Child(format.Meta(" ClockSysvar", inst.AccountMetaSlice[1]))
accountsBranch.Child(format.Meta("CurrentAuthority", inst.AccountMetaSlice[2]))
accountsBranch.Child(format.Meta(" NewAuthority", inst.AccountMetaSlice[3]))
})
})
})
}
22 changes: 22 additions & 0 deletions programs/vote/AuthorizeChecked_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package vote

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestRoundTrip_AuthorizeChecked(t *testing.T) {
inst := NewAuthorizeCheckedInstruction(VoteAuthorizeVoter, pubkeyOf(1), pubkeyOf(2), pubkeyOf(3))
data, err := encodeInst(inst)
require.NoError(t, err)
require.Equal(t, u32LE(Instruction_AuthorizeChecked), data[:4])

expected := concat(u32LE(Instruction_AuthorizeChecked), u32LE(uint32(VoteAuthorizeVoter)))
require.Equal(t, expected, data)

decoded, err := DecodeInstruction(nil, data)
require.NoError(t, err)
ac := decoded.Impl.(*AuthorizeChecked)
require.Equal(t, VoteAuthorizeVoter, *ac.VoteAuthorize)
}
Loading
Loading