forked from gagliardetto/solana-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support ComputeBudgetProgram instructions (gagliardetto#132)
* feat: implement ComputeBudget instructions * better naming * tests * fix: missing account gettable * feat: add MAX_COMPUTE_UNIT_LIMIT and MAX_HEAP_FRAME_BYTES * tests: more
- Loading branch information
Showing
10 changed files
with
934 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright 2021 github.com/gagliardetto | ||
// | ||
// 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 computebudget | ||
|
||
import ( | ||
"errors" | ||
|
||
ag_binary "github.com/gagliardetto/binary" | ||
ag_solanago "github.com/gagliardetto/solana-go" | ||
ag_format "github.com/gagliardetto/solana-go/text/format" | ||
ag_treeout "github.com/gagliardetto/treeout" | ||
) | ||
|
||
const MAX_HEAP_FRAME_BYTES uint32 = 256 * 1024 | ||
|
||
type RequestHeapFrame struct { | ||
HeapSize uint32 | ||
} | ||
|
||
func (obj *RequestHeapFrame) SetAccounts(accounts []*ag_solanago.AccountMeta) error { | ||
return nil | ||
} | ||
|
||
func (slice RequestHeapFrame) GetAccounts() (accounts []*ag_solanago.AccountMeta) { | ||
return | ||
} | ||
|
||
// NewRequestHeapFrameInstructionBuilder creates a new `RequestHeapFrame` instruction builder. | ||
func NewRequestHeapFrameInstructionBuilder() *RequestHeapFrame { | ||
nd := &RequestHeapFrame{} | ||
return nd | ||
} | ||
|
||
// Request heap frame in bytes | ||
func (inst *RequestHeapFrame) SetHeapSize(heapSize uint32) *RequestHeapFrame { | ||
inst.HeapSize = heapSize | ||
return inst | ||
} | ||
|
||
func (inst RequestHeapFrame) Build() *Instruction { | ||
return &Instruction{BaseVariant: ag_binary.BaseVariant{ | ||
Impl: inst, | ||
TypeID: ag_binary.TypeIDFromUint8(Instruction_RequestHeapFrame), | ||
}} | ||
} | ||
|
||
// ValidateAndBuild validates the instruction parameters and accounts; | ||
// if there is a validation error, it returns the error. | ||
// Otherwise, it builds and returns the instruction. | ||
func (inst RequestHeapFrame) ValidateAndBuild() (*Instruction, error) { | ||
if err := inst.Validate(); err != nil { | ||
return nil, err | ||
} | ||
return inst.Build(), nil | ||
} | ||
|
||
func (inst *RequestHeapFrame) Validate() error { | ||
// Check whether all (required) parameters are set: | ||
{ | ||
if inst.HeapSize == 0 { | ||
return errors.New("HeapSize parameter is not set") | ||
} | ||
if inst.HeapSize > MAX_HEAP_FRAME_BYTES { | ||
return errors.New("HeapSize parameter exceeds the maximum heap frame bytes") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (inst *RequestHeapFrame) EncodeToTree(parent ag_treeout.Branches) { | ||
parent.Child(ag_format.Program(ProgramName, ProgramID)). | ||
// | ||
ParentFunc(func(programBranch ag_treeout.Branches) { | ||
programBranch.Child(ag_format.Instruction("RequestHeapFrame")). | ||
// | ||
ParentFunc(func(instructionBranch ag_treeout.Branches) { | ||
|
||
// Parameters of the instruction: | ||
instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) { | ||
paramsBranch.Child(ag_format.Param("HeapSize", inst.HeapSize)) | ||
}) | ||
}) | ||
}) | ||
} | ||
|
||
func (obj RequestHeapFrame) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { | ||
// Serialize `HeapSize` param: | ||
err = encoder.Encode(obj.HeapSize) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
func (obj *RequestHeapFrame) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { | ||
// Deserialize `HeapSize`: | ||
err = decoder.Decode(&obj.HeapSize) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// NewRequestHeapFrameInstruction declares a new RequestHeapFrame instruction with the provided parameters and accounts. | ||
func NewRequestHeapFrameInstruction( | ||
// Parameters: | ||
heapSize uint32, | ||
) *RequestHeapFrame { | ||
return NewRequestHeapFrameInstructionBuilder().SetHeapSize(heapSize) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2021 github.com/gagliardetto | ||
// | ||
// 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 computebudget | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestRequestHeapFrameInstruction(t *testing.T) { | ||
|
||
t.Run("should validate max heap size", func(t *testing.T) { | ||
_, err := NewRequestHeapFrameInstruction(300000).ValidateAndBuild() | ||
require.Error(t, err) | ||
}) | ||
|
||
t.Run("should build ix", func(t *testing.T) { | ||
ix, err := NewRequestHeapFrameInstruction(4000).ValidateAndBuild() | ||
require.Nil(t, err) | ||
|
||
require.Equal(t, ProgramID, ix.ProgramID()) | ||
require.Equal(t, 0, len(ix.Accounts())) | ||
|
||
data, err := ix.Data() | ||
require.Nil(t, err) | ||
require.Equal(t, []byte{0x1, 0xa0, 0xf, 0x0, 0x0}, data) | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// Copyright 2021 github.com/gagliardetto | ||
// | ||
// 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 computebudget | ||
|
||
import ( | ||
"errors" | ||
|
||
ag_binary "github.com/gagliardetto/binary" | ||
ag_solanago "github.com/gagliardetto/solana-go" | ||
ag_format "github.com/gagliardetto/solana-go/text/format" | ||
ag_treeout "github.com/gagliardetto/treeout" | ||
) | ||
|
||
type RequestUnitsDeprecated struct { | ||
// Units to request | ||
Units uint32 | ||
|
||
// Additional fee to add | ||
AdditionalFee uint32 | ||
} | ||
|
||
func (obj *RequestUnitsDeprecated) SetAccounts(accounts []*ag_solanago.AccountMeta) error { | ||
return nil | ||
} | ||
|
||
func (slice RequestUnitsDeprecated) GetAccounts() (accounts []*ag_solanago.AccountMeta) { | ||
return | ||
} | ||
|
||
// NewRequestUnitsDeprecatedInstructionBuilder creates a new `RequestUnitsDeprecated` instruction builder. | ||
func NewRequestUnitsDeprecatedInstructionBuilder() *RequestUnitsDeprecated { | ||
nd := &RequestUnitsDeprecated{} | ||
return nd | ||
} | ||
|
||
// Units to request | ||
func (inst *RequestUnitsDeprecated) SetUnits(units uint32) *RequestUnitsDeprecated { | ||
inst.Units = units | ||
return inst | ||
} | ||
|
||
// Additional fee to add | ||
func (inst *RequestUnitsDeprecated) SetAdditionalFee(additionalFee uint32) *RequestUnitsDeprecated { | ||
inst.AdditionalFee = additionalFee | ||
return inst | ||
} | ||
|
||
func (inst RequestUnitsDeprecated) Build() *Instruction { | ||
return &Instruction{BaseVariant: ag_binary.BaseVariant{ | ||
Impl: inst, | ||
TypeID: ag_binary.TypeIDFromUint8(Instruction_RequestUnitsDeprecated), | ||
}} | ||
} | ||
|
||
// ValidateAndBuild validates the instruction parameters and accounts; | ||
// if there is a validation error, it returns the error. | ||
// Otherwise, it builds and returns the instruction. | ||
func (inst RequestUnitsDeprecated) ValidateAndBuild() (*Instruction, error) { | ||
if err := inst.Validate(); err != nil { | ||
return nil, err | ||
} | ||
return inst.Build(), nil | ||
} | ||
|
||
func (inst *RequestUnitsDeprecated) Validate() error { | ||
// Check whether all (required) parameters are set: | ||
{ | ||
if inst.Units == 0 { | ||
return errors.New("Units parameter is not set") | ||
} | ||
if inst.Units > MAX_COMPUTE_UNIT_LIMIT { | ||
return errors.New("Units parameter exceeds the maximum compute unit") | ||
} | ||
if inst.AdditionalFee == 0 { | ||
return errors.New("AdditionalFee parameter is not set") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (inst *RequestUnitsDeprecated) EncodeToTree(parent ag_treeout.Branches) { | ||
parent.Child(ag_format.Program(ProgramName, ProgramID)). | ||
// | ||
ParentFunc(func(programBranch ag_treeout.Branches) { | ||
programBranch.Child(ag_format.Instruction("RequestUnitsDeprecated")). | ||
// | ||
ParentFunc(func(instructionBranch ag_treeout.Branches) { | ||
|
||
// Parameters of the instruction: | ||
instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) { | ||
paramsBranch.Child(ag_format.Param(" Units", inst.Units)) | ||
paramsBranch.Child(ag_format.Param("AdditionalFee", inst.AdditionalFee)) | ||
}) | ||
}) | ||
}) | ||
} | ||
|
||
func (obj RequestUnitsDeprecated) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { | ||
// Serialize `Units` param: | ||
err = encoder.Encode(obj.Units) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Serialize `AdditionalFee` param: | ||
err = encoder.Encode(obj.AdditionalFee) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
func (obj *RequestUnitsDeprecated) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { | ||
// Deserialize `Units`: | ||
err = decoder.Decode(&obj.Units) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Deserialize `AdditionalFee`: | ||
err = decoder.Decode(&obj.AdditionalFee) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// NewRequestUnitsDeprecatedInstruction declares a new RequestUnitsDeprecated instruction with the provided parameters and accounts. | ||
func NewRequestUnitsDeprecatedInstruction( | ||
// Parameters: | ||
units uint32, | ||
additionalFee uint32, | ||
) *RequestUnitsDeprecated { | ||
return NewRequestUnitsDeprecatedInstructionBuilder(). | ||
SetUnits(units). | ||
SetAdditionalFee(additionalFee) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2021 github.com/gagliardetto | ||
// | ||
// 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 computebudget | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestNewRequestUnitsDeprecatedInstruction(t *testing.T) { | ||
|
||
t.Run("should validate max units", func(t *testing.T) { | ||
_, err := NewRequestUnitsDeprecatedInstruction(2000000, 1000).ValidateAndBuild() | ||
require.Error(t, err) | ||
}) | ||
|
||
t.Run("should build request units ix", func(t *testing.T) { | ||
ix, err := NewRequestUnitsDeprecatedInstruction(1400000, 1000).ValidateAndBuild() | ||
require.Nil(t, err) | ||
|
||
require.Equal(t, ProgramID, ix.ProgramID()) | ||
require.Equal(t, 0, len(ix.Accounts())) | ||
|
||
data, err := ix.Data() | ||
require.Nil(t, err) | ||
require.Equal(t, []byte{0x0, 0xc0, 0x5c, 0x15, 0x0, 0xe8, 0x3, 0x0, 0x0}, data) | ||
}) | ||
|
||
} |
Oops, something went wrong.