Upgrade to latest RPC spec
This commit is contained in:
parent
259ffea731
commit
8aa9b205c6
141
README.md
141
README.md
|
@ -74,7 +74,7 @@ More contracts to come.
|
|||
|
||||
There is currently **no stable release**. The SDK is actively developed and latest is `v1.2.1` which is an `alpha` release.
|
||||
|
||||
The RPC and WS client implementation is based on [this RPC spec](https://github.com/solana-labs/solana/blob/dff9c88193da142693cabebfcd3bf68fa8e8b873/docs/src/developing/clients/jsonrpc-api.md).
|
||||
The RPC and WS client implementation is based on [this RPC spec](https://github.com/solana-labs/solana/blob/c2435363f39723cef59b91322f3b6a815008af29/docs/src/developing/clients/jsonrpc-api.md).
|
||||
|
||||
Note
|
||||
----
|
||||
|
@ -645,19 +645,22 @@ func main() {
|
|||
- [GetBlocks](#index--rpc--getblocks)
|
||||
- [GetBlocksWithLimit](#index--rpc--getblockswithlimit)
|
||||
- [GetClusterNodes](#index--rpc--getclusternodes)
|
||||
- [GetConfirmedBlock](#index--rpc--getconfirmedblock)
|
||||
- [GetConfirmedBlocks](#index--rpc--getconfirmedblocks)
|
||||
- [GetConfirmedBlocksWithLimit](#index--rpc--getconfirmedblockswithlimit)
|
||||
- [GetConfirmedSignaturesForAddress2](#index--rpc--getconfirmedsignaturesforaddress2)
|
||||
- [GetConfirmedTransaction](#index--rpc--getconfirmedtransaction)
|
||||
- [GetConfirmedBlock](#index--rpc--getconfirmedblock) **DEPRECATED: Please use [GetBlock](#index--rpc--getblock) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetConfirmedBlocks](#index--rpc--getconfirmedblocks) **DEPRECATED: Please use [GetBlocks](#index--rpc--getblocks) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetConfirmedBlocksWithLimit](#index--rpc--getconfirmedblockswithlimit) **DEPRECATED: Please use [GetBlocksWithLimit](#index--rpc--getblockswithlimit) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetConfirmedSignaturesForAddress2](#index--rpc--getconfirmedsignaturesforaddress2) **DEPRECATED: Please use [GetSignaturesForAddress](#index--rpc--getsignaturesforaddress) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetConfirmedTransaction](#index--rpc--getconfirmedtransaction) **DEPRECATED: Please use [GetTransaction](#index--rpc--gettransaction) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetEpochInfo](#index--rpc--getepochinfo)
|
||||
- [GetEpochSchedule](#index--rpc--getepochschedule)
|
||||
- [GetFeeCalculatorForBlockhash](#index--rpc--getfeecalculatorforblockhash)
|
||||
- [GetFeeRateGovernor](#index--rpc--getfeerategovernor)
|
||||
- [GetFees](#index--rpc--getfees)
|
||||
- [GetFeeCalculatorForBlockhash](#index--rpc--getfeecalculatorforblockhash) **DEPRECATED: Please use [IsBlockhashValid](#index--rpc--isblockhashvalid) or [GetFeeForMessage](#index--rpc--getfeeformessage) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetFeeRateGovernor](#index--rpc--getfeerategovernor) **DEPRECATED**
|
||||
- [GetFees](#index--rpc--getfees) **DEPRECATED: Please use [GetFeeForMessage](#index--rpc--getfeeformessage) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetFeeForMessage](#index--rpc--getfeeformessage)
|
||||
- [GetFirstAvailableBlock](#index--rpc--getfirstavailableblock)
|
||||
- [GetGenesisHash](#index--rpc--getgenesishash)
|
||||
- [GetHealth](#index--rpc--gethealth)
|
||||
- [GetHighestSnapshotSlot](#index--rpc--gethighestsnapshotslot)
|
||||
- [GetLatestBlockhash](#index--rpc--getlatestblockhash)
|
||||
- [GetIdentity](#index--rpc--getidentity)
|
||||
- [GetInflationGovernor](#index--rpc--getinflationgovernor)
|
||||
- [GetInflationRate](#index--rpc--getinflationrate)
|
||||
|
@ -669,14 +672,14 @@ func main() {
|
|||
- [GetMinimumBalanceForRentExemption](#index--rpc--getminimumbalanceforrentexemption)
|
||||
- [GetMultipleAccounts](#index--rpc--getmultipleaccounts)
|
||||
- [GetProgramAccounts](#index--rpc--getprogramaccounts)
|
||||
- [GetRecentBlockhash](#index--rpc--getrecentblockhash)
|
||||
- [GetRecentBlockhash](#index--rpc--getrecentblockhash) **DEPRECATED: Please use [GetFeeForMessage](#index--rpc--getfeeformessage) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetRecentPerformanceSamples](#index--rpc--getrecentperformancesamples)
|
||||
- [GetSignatureStatuses](#index--rpc--getsignaturestatuses)
|
||||
- [GetSignaturesForAddress](#index--rpc--getsignaturesforaddress)
|
||||
- [GetSlot](#index--rpc--getslot)
|
||||
- [GetSlotLeader](#index--rpc--getslotleader)
|
||||
- [GetSlotLeaders](#index--rpc--getslotleaders)
|
||||
- [GetSnapshotSlot](#index--rpc--getsnapshotslot)
|
||||
- [GetSnapshotSlot](#index--rpc--getsnapshotslot) **DEPRECATED: Please use [GetHighestSnapshotSlot](#index--rpc--gethighestsnapshotslot) instead** (This method is expected to be removed in **solana-core v2.0**)
|
||||
- [GetStakeActivation](#index--rpc--getstakeactivation)
|
||||
- [GetSupply](#index--rpc--getsupply)
|
||||
- [GetTokenAccountBalance](#index--rpc--gettokenaccountbalance)
|
||||
|
@ -688,6 +691,7 @@ func main() {
|
|||
- [GetTransactionCount](#index--rpc--gettransactioncount)
|
||||
- [GetVersion](#index--rpc--getversion)
|
||||
- [GetVoteAccounts](#index--rpc--getvoteaccounts)
|
||||
- [IsBlockhashValid](#index--rpc--isblockhashvalid)
|
||||
- [MinimumLedgerSlot](#index--rpc--minimumledgerslot)
|
||||
- [RequestAirdrop](#index--rpc--requestairdrop)
|
||||
- [SendTransaction](#index--rpc--sendtransaction)
|
||||
|
@ -1497,6 +1501,35 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > GetFeeForMessage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetFeeForMessage(
|
||||
context.Background(),
|
||||
"AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA",
|
||||
rpc.CommitmentProcessed,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > GetFirstAvailableBlock
|
||||
|
||||
```go
|
||||
|
@ -1576,6 +1609,59 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > GetHighestSnapshotSlot
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetHighestSnapshotSlot(
|
||||
context.Background(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > GetLatestBlockhash
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetLatestBlockhash(
|
||||
context.Background(),
|
||||
rpc.CommitmentFinalized,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > GetIdentity
|
||||
|
||||
```go
|
||||
|
@ -2507,6 +2593,39 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > IsBlockhashValid
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.MainNetBeta_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
blockHash := solana.MustHashFromBase58("J7rBdM6AecPDEZp8aPq5iPSNKVkU5Q76F3oAV4eW5wsW")
|
||||
out, err := client.IsBlockhashValid(
|
||||
context.TODO(),
|
||||
blockHash,
|
||||
rpc.CommitmentFinalized,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(out)
|
||||
spew.Dump(out.Value) // true or false
|
||||
|
||||
fmt.Println("is blockhash valid:", out.Value)
|
||||
}
|
||||
```
|
||||
|
||||
#### [index](#contents) > [RPC](#rpc-methods) > MinimumLedgerSlot
|
||||
|
||||
```go
|
||||
|
|
|
@ -75,7 +75,7 @@ var getTransactionsCmd = &cobra.Command{
|
|||
return fmt.Errorf("unable to get confirmed transaction with signature %q: %s", cs.Signature, ct.Meta.Err)
|
||||
}
|
||||
|
||||
_, err = ct.Transaction.EncodeTree(text.NewTreeEncoder(os.Stdout, text.Bold("INSTRUCTIONS")))
|
||||
_, err = ct.MustGetTransaction().EncodeTree(text.NewTreeEncoder(os.Stdout, text.Bold("INSTRUCTIONS")))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
12
keys.go
12
keys.go
|
@ -208,13 +208,13 @@ func (p PublicKey) Short(n int) string {
|
|||
}
|
||||
|
||||
func formatShortPubkey(n int, pubkey PublicKey) string {
|
||||
if n > 10 {
|
||||
n = 10
|
||||
}
|
||||
if n < 3 {
|
||||
n = 3
|
||||
}
|
||||
str := pubkey.String()
|
||||
if n > (len(str)/2)-1 {
|
||||
n = (len(str) / 2) - 1
|
||||
}
|
||||
if n < 2 {
|
||||
n = 2
|
||||
}
|
||||
return str[:n] + "..." + str[len(str)-n:]
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package solana
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
bin "github.com/gagliardetto/binary"
|
||||
|
@ -101,6 +102,11 @@ func (mx *Message) MarshalWithEncoder(encoder *bin.Encoder) error {
|
|||
return encoder.WriteBytes(out, false)
|
||||
}
|
||||
|
||||
func (mx Message) ToBase64() string {
|
||||
out, _ := mx.MarshalBinary()
|
||||
return base64.StdEncoding.EncodeToString(out)
|
||||
}
|
||||
|
||||
func (mx *Message) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) {
|
||||
{
|
||||
mx.Header.NumRequiredSignatures, err = decoder.ReadUint8()
|
||||
|
@ -158,7 +164,6 @@ func (mx *Message) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compInst.AccountCount = bin.Varuint16(numAccounts)
|
||||
for i := 0; i < numAccounts; i++ {
|
||||
accountIndex, err := decoder.ReadUint8()
|
||||
if err != nil {
|
||||
|
@ -176,7 +181,6 @@ func (mx *Message) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compInst.DataLength = bin.Varuint16(dataLen)
|
||||
compInst.Data = Base58(dataBytes)
|
||||
}
|
||||
mx.Instructions = append(mx.Instructions, compInst)
|
||||
|
|
|
@ -157,7 +157,7 @@ func TestClient_GetConfirmedSignaturesForAddress2(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetConfirmedTransaction(t *testing.T) {
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(`{"jsonrpc":"2.0","result":{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":[],"postBalances":[],"preBalances":[],"status":{"Ok":null}},"slot":48291656,"transaction":{"message":{"accountKeys":["GKu2xfGZopa8C9K11wduQWgP4W4H7EEcaNdsUb7mxhyr"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"3yZe7d","programIdIndex":4}],"recentBlockhash":"uoEAQCWCKjV9ecsBvngctJ7upNBZX7hpN4SfdR6TaUz"},"signatures":["53hoZ98EsCMA6L63GWM65M3Bd3WqA4LxD8bcJkbKoKWhbJFqX9M1WZ4fSjt8bYyZn21NwNnV2A25zirBni9Qk6LR"]}},"id":0}`))
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(`{"jsonrpc":"2.0","result":{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":[],"postBalances":[],"preBalances":[],"status":{"Ok":null}},"slot":48291656,"transaction":["AcpmPgtaSCzI2vuOUXduljmnoc1zIqMETzEJ8zmF+\/yy2AABHMNonpVleveVw4a4Fo7LUDWtxo2FkyzFr2x9DQIBAAMB47aX3y9Dfp+\/ycSDXt0Ph3TfZQBqPSXMQYToKtUtr5kNhniVeV7Las6qkeV8d0rksxV9de0GF7p4nzQUVEnrWwEEBAECAwAEdGVzdA==","base64"]},"id":0}`))
|
||||
defer closer()
|
||||
client := New(server.URL)
|
||||
|
||||
|
@ -183,29 +183,28 @@ func TestClient_GetConfirmedTransaction(t *testing.T) {
|
|||
signature, err := solana.SignatureFromBase58("53hoZ98EsCMA6L63GWM65M3Bd3WqA4LxD8bcJkbKoKWhbJFqX9M1WZ4fSjt8bYyZn21NwNnV2A25zirBni9Qk6LR")
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, &TransactionWithMeta{
|
||||
Transaction: &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
Header: solana.MessageHeader{NumRequiredSignatures: 1, NumReadonlySignedAccounts: 0, NumReadonlyUnsignedAccounts: 3},
|
||||
RecentBlockhash: solana.MustHashFromBase58("uoEAQCWCKjV9ecsBvngctJ7upNBZX7hpN4SfdR6TaUz"),
|
||||
AccountKeys: []solana.PublicKey{solana.MustPublicKeyFromBase58("GKu2xfGZopa8C9K11wduQWgP4W4H7EEcaNdsUb7mxhyr")},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{Accounts: []uint16{1, 2, 3, 0}, Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}), ProgramIDIndex: 4},
|
||||
},
|
||||
},
|
||||
Signatures: []solana.Signature{signature},
|
||||
assert.Equal(t, &TransactionMeta{
|
||||
Fee: 5000,
|
||||
PreBalances: []uint64{},
|
||||
PostBalances: []uint64{},
|
||||
InnerInstructions: []InnerInstruction{},
|
||||
LogMessages: []string{},
|
||||
Status: DeprecatedTransactionMetaStatus{
|
||||
"Ok": nil,
|
||||
},
|
||||
Meta: &TransactionMeta{
|
||||
Fee: 5000,
|
||||
PreBalances: []uint64{},
|
||||
PostBalances: []uint64{},
|
||||
InnerInstructions: []InnerInstruction{},
|
||||
LogMessages: []string{},
|
||||
Status: DeprecatedTransactionMetaStatus{
|
||||
"Ok": nil,
|
||||
}, out.Meta)
|
||||
|
||||
assert.Equal(t, &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
Header: solana.MessageHeader{NumRequiredSignatures: 1, NumReadonlySignedAccounts: 0, NumReadonlyUnsignedAccounts: 3},
|
||||
RecentBlockhash: solana.MustHashFromBase58("uoEAQCWCKjV9ecsBvngctJ7upNBZX7hpN4SfdR6TaUz"),
|
||||
AccountKeys: []solana.PublicKey{solana.MustPublicKeyFromBase58("GKu2xfGZopa8C9K11wduQWgP4W4H7EEcaNdsUb7mxhyr")},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{Accounts: []uint16{1, 2, 3, 0}, Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}), ProgramIDIndex: 4},
|
||||
},
|
||||
},
|
||||
}, out)
|
||||
Signatures: []solana.Signature{signature},
|
||||
}, out.MustGetTransaction())
|
||||
}
|
||||
|
||||
// mustAnyToJSON marshals the provided variable
|
||||
|
@ -323,7 +322,7 @@ func TestClient_GetBalance(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetBlock(t *testing.T) {
|
||||
responseBody := `{"blockHeight":69213636,"blockTime":1625227950,"blockhash":"5M77sHdwzH6rckuQwF8HL1w52n7hjrh4GVTFiF6T8QyB","parentSlot":83987983,"previousBlockhash":"Aq9jSXe1jRzfiaBcRFLe4wm7j499vWVEeFQrq5nnXfZN","rewards":[{"lamports":1595000,"postBalance":482032983798,"pubkey":"5rL3AaidKJa4ChSV3ys1SvpDg9L4amKiwYayGR5oL3dq","rewardType":"Fee"}],"transactions":[{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":["Program Vote111111111111111111111111111111111111111 invoke [1]","Program Vote111111111111111111111111111111111111111 success"],"postBalances":[441866063495,40905918933763,1,1,1],"postTokenBalances":[],"preBalances":[441866068495,40905918933763,1,1,1],"preTokenBalances":[],"rewards":[],"status":{"Ok":null}},"transaction":{"message":{"accountKeys":["EVd8FFVB54svYdZdG6hH4F4hTbqre5mpQ7XyF5rKUmes","72miaovmbPqccdbAA861r2uxwB5yL1sMjrgbCnc4JfVT","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"3yZe7d","programIdIndex":4}],"recentBlockhash":"CnyzpJmBydX1X2FyXXzsPFc5WPT9UFdLVkEhnvW33at"},"signatures":["D8emaP3CaepSGigD3TCrev7j67yPLMi82qfzTb9iZYPxHcCmm6sQBKTU4bzAee4445zbnbWduVAZ87WfbWbXoAU"]}},{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":["Program Vote111111111111111111111111111111111111111 invoke [1]","Program Vote111111111111111111111111111111111111111 success"],"postBalances":[334759887662,151357332545078,1,1,1],"postTokenBalances":[],"preBalances":[334759892662,151357332545078,1,1,1],"preTokenBalances":[],"rewards":[],"status":{"Ok":null}},"transaction":{"message":{"accountKeys":["5rxRt2GVpSUFJTqQ5E4urqJCDbcBPakb46t6URyxQ5Za","HdzdTTjrmRLYVRy3umzZX4NcUmGTHu6hvYLQN2jGJo53","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"3yZe7d","programIdIndex":4}],"recentBlockhash":"BL8oo42yoSTKUYpbXR3kdxeV5X1P8JUUZBZaeBL8K6G"},"signatures":["xvrkWXwj5h9SsJvboPMtn4jbR6XNmnHYp4MAikKFwdtkpwMxceFZ46QRzeyGUqm5P1kmCagdUubr3aPdxo7vzyq"]}}]}`
|
||||
responseBody := `{"blockHeight":69213636,"blockTime":1625227950,"blockhash":"5M77sHdwzH6rckuQwF8HL1w52n7hjrh4GVTFiF6T8QyB","parentSlot":83987983,"previousBlockhash":"Aq9jSXe1jRzfiaBcRFLe4wm7j499vWVEeFQrq5nnXfZN","rewards":[{"lamports":1595000,"postBalance":482032983798,"pubkey":"5rL3AaidKJa4ChSV3ys1SvpDg9L4amKiwYayGR5oL3dq","rewardType":"Fee"}],"transactions":[{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":["Program Vote111111111111111111111111111111111111111 invoke [1]","Program Vote111111111111111111111111111111111111111 success"],"postBalances":[441866063495,40905918933763,1,1,1],"postTokenBalances":[],"preBalances":[441866068495,40905918933763,1,1,1],"preTokenBalances":[],"rewards":[],"status":{"Ok":null}},"transaction":["AQp2TH1spzjBAVM3alvnpaePFx3YEo9dvRglDuSChZUoTMD\/\/2h0HY5+89LJjCdiGJ7Ph3+Fyvbeiz1uJF8gxw0BAAMFyH0KDkXtjL1xebUYflZxYGlpV+LvjazzZCb\/mF2T67xZmkOUM\/A0iDSEkFzD5m4Ol82vsojigvqxrmp7Z1vrQgan1RcZLwqvxvJl4\/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ\/wNo1OAAAAAAAMFYbeqrsxJ9\/vZxtOaFi3rT2w9RF5Xi4jsyu61f3t1AQQEAQIDAAR0ZXN0","base64"]},{"meta":{"err":null,"fee":5000,"innerInstructions":[],"logMessages":["Program Vote111111111111111111111111111111111111111 invoke [1]","Program Vote111111111111111111111111111111111111111 success"],"postBalances":[334759887662,151357332545078,1,1,1],"postTokenBalances":[],"preBalances":[334759892662,151357332545078,1,1,1],"preTokenBalances":[],"rewards":[],"status":{"Ok":null}},"transaction":["ATA7DkBatbe2JB43QV+QRj2yoXSMXXttYFggDxZYOBfsRyYuGtzrbUevivclchxVccRIPlRP9PtS\/9NPXlwmhwwBAAMFSDrhjiNPuNqc4BWwitZz7xJ2NIXtv6XZtwtEOmgLj3n3NQ+OONLFlsu0LoUBSDsp40i9jOjZJBsliMtvTfdV+gan1RcZLwqvxvJl4\/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ\/wNo1OAAAAAAAKlcZMqS\/Oh0v+kOq2Ipg73NqbvKBRGQJDK8\/01K+MBAQQEAQIDAAR0ZXN0","base64"]}]}`
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
|
||||
defer closer()
|
||||
|
||||
|
@ -344,7 +343,7 @@ func TestClient_GetBlock(t *testing.T) {
|
|||
"params": []interface{}{
|
||||
float64(block),
|
||||
map[string]interface{}{
|
||||
"encoding": string(solana.EncodingJSON),
|
||||
"encoding": string(solana.EncodingBase64),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -354,6 +353,66 @@ func TestClient_GetBlock(t *testing.T) {
|
|||
// TODO:
|
||||
// - test also when requesting only signatures
|
||||
|
||||
tx1 := &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
AccountKeys: []solana.PublicKey{
|
||||
solana.MustPublicKeyFromBase58("EVd8FFVB54svYdZdG6hH4F4hTbqre5mpQ7XyF5rKUmes"),
|
||||
solana.MustPublicKeyFromBase58("72miaovmbPqccdbAA861r2uxwB5yL1sMjrgbCnc4JfVT"),
|
||||
solana.MustPublicKeyFromBase58("SysvarS1otHashes111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("SysvarC1ock11111111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111"),
|
||||
},
|
||||
Header: solana.MessageHeader{
|
||||
NumReadonlySignedAccounts: 0,
|
||||
NumReadonlyUnsignedAccounts: 3,
|
||||
NumRequiredSignatures: 1,
|
||||
},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{
|
||||
Accounts: []uint16{1, 2, 3, 0},
|
||||
Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}),
|
||||
ProgramIDIndex: 4,
|
||||
},
|
||||
},
|
||||
RecentBlockhash: solana.MustHashFromBase58("CnyzpJmBydX1X2FyXXzsPFc5WPT9UFdLVkEhnvW33at"),
|
||||
},
|
||||
Signatures: []solana.Signature{
|
||||
solana.MustSignatureFromBase58("D8emaP3CaepSGigD3TCrev7j67yPLMi82qfzTb9iZYPxHcCmm6sQBKTU4bzAee4445zbnbWduVAZ87WfbWbXoAU"),
|
||||
},
|
||||
}
|
||||
tx1Data, err := DataBytesOrJSONFromBase64(tx1.MustToBase64())
|
||||
require.NoError(t, err)
|
||||
|
||||
tx2 := &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
AccountKeys: []solana.PublicKey{
|
||||
solana.MustPublicKeyFromBase58("5rxRt2GVpSUFJTqQ5E4urqJCDbcBPakb46t6URyxQ5Za"),
|
||||
solana.MustPublicKeyFromBase58("HdzdTTjrmRLYVRy3umzZX4NcUmGTHu6hvYLQN2jGJo53"),
|
||||
solana.MustPublicKeyFromBase58("SysvarS1otHashes111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("SysvarC1ock11111111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111"),
|
||||
},
|
||||
Header: solana.MessageHeader{
|
||||
NumReadonlySignedAccounts: 0,
|
||||
NumReadonlyUnsignedAccounts: 3,
|
||||
NumRequiredSignatures: 1,
|
||||
},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{
|
||||
Accounts: []uint16{1, 2, 3, 0},
|
||||
Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}),
|
||||
ProgramIDIndex: 4,
|
||||
},
|
||||
},
|
||||
RecentBlockhash: solana.MustHashFromBase58("BL8oo42yoSTKUYpbXR3kdxeV5X1P8JUUZBZaeBL8K6G"),
|
||||
},
|
||||
Signatures: []solana.Signature{
|
||||
solana.MustSignatureFromBase58("xvrkWXwj5h9SsJvboPMtn4jbR6XNmnHYp4MAikKFwdtkpwMxceFZ46QRzeyGUqm5P1kmCagdUubr3aPdxo7vzyq"),
|
||||
},
|
||||
}
|
||||
tx2Data, err := DataBytesOrJSONFromBase64(tx2.MustToBase64())
|
||||
require.NoError(t, err)
|
||||
|
||||
blockTime := solana.UnixTimeSeconds(1625227950)
|
||||
assert.Equal(t,
|
||||
&GetBlockResult{
|
||||
|
@ -392,33 +451,7 @@ func TestClient_GetBlock(t *testing.T) {
|
|||
"Ok": nil,
|
||||
},
|
||||
},
|
||||
Transaction: &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
AccountKeys: []solana.PublicKey{
|
||||
solana.MustPublicKeyFromBase58("EVd8FFVB54svYdZdG6hH4F4hTbqre5mpQ7XyF5rKUmes"),
|
||||
solana.MustPublicKeyFromBase58("72miaovmbPqccdbAA861r2uxwB5yL1sMjrgbCnc4JfVT"),
|
||||
solana.MustPublicKeyFromBase58("SysvarS1otHashes111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("SysvarC1ock11111111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111"),
|
||||
},
|
||||
Header: solana.MessageHeader{
|
||||
NumReadonlySignedAccounts: 0,
|
||||
NumReadonlyUnsignedAccounts: 3,
|
||||
NumRequiredSignatures: 1,
|
||||
},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{
|
||||
Accounts: []uint16{1, 2, 3, 0},
|
||||
Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}),
|
||||
ProgramIDIndex: 4,
|
||||
},
|
||||
},
|
||||
RecentBlockhash: solana.MustHashFromBase58("CnyzpJmBydX1X2FyXXzsPFc5WPT9UFdLVkEhnvW33at"),
|
||||
},
|
||||
Signatures: []solana.Signature{
|
||||
solana.MustSignatureFromBase58("D8emaP3CaepSGigD3TCrev7j67yPLMi82qfzTb9iZYPxHcCmm6sQBKTU4bzAee4445zbnbWduVAZ87WfbWbXoAU"),
|
||||
},
|
||||
},
|
||||
Transaction: tx1Data,
|
||||
},
|
||||
{
|
||||
Meta: &TransactionMeta{
|
||||
|
@ -441,33 +474,7 @@ func TestClient_GetBlock(t *testing.T) {
|
|||
"Ok": nil,
|
||||
},
|
||||
},
|
||||
Transaction: &solana.Transaction{
|
||||
Message: solana.Message{
|
||||
AccountKeys: []solana.PublicKey{
|
||||
solana.MustPublicKeyFromBase58("5rxRt2GVpSUFJTqQ5E4urqJCDbcBPakb46t6URyxQ5Za"),
|
||||
solana.MustPublicKeyFromBase58("HdzdTTjrmRLYVRy3umzZX4NcUmGTHu6hvYLQN2jGJo53"),
|
||||
solana.MustPublicKeyFromBase58("SysvarS1otHashes111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("SysvarC1ock11111111111111111111111111111111"),
|
||||
solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111"),
|
||||
},
|
||||
Header: solana.MessageHeader{
|
||||
NumReadonlySignedAccounts: 0,
|
||||
NumReadonlyUnsignedAccounts: 3,
|
||||
NumRequiredSignatures: 1,
|
||||
},
|
||||
Instructions: []solana.CompiledInstruction{
|
||||
{
|
||||
Accounts: []uint16{1, 2, 3, 0},
|
||||
Data: solana.Base58([]byte{0x74, 0x65, 0x73, 0x74}),
|
||||
ProgramIDIndex: 4,
|
||||
},
|
||||
},
|
||||
RecentBlockhash: solana.MustHashFromBase58("BL8oo42yoSTKUYpbXR3kdxeV5X1P8JUUZBZaeBL8K6G"),
|
||||
},
|
||||
Signatures: []solana.Signature{
|
||||
solana.MustSignatureFromBase58("xvrkWXwj5h9SsJvboPMtn4jbR6XNmnHYp4MAikKFwdtkpwMxceFZ46QRzeyGUqm5P1kmCagdUubr3aPdxo7vzyq"),
|
||||
},
|
||||
},
|
||||
Transaction: tx2Data,
|
||||
},
|
||||
},
|
||||
}, out)
|
||||
|
@ -501,7 +508,7 @@ func TestClient_GetBlockWithOpts(t *testing.T) {
|
|||
"params": []interface{}{
|
||||
float64(block),
|
||||
map[string]interface{}{
|
||||
"encoding": string(solana.EncodingJSON),
|
||||
"encoding": string(solana.EncodingBase64),
|
||||
"transactionDetails": string(TransactionDetailsSignatures),
|
||||
"rewards": rewards,
|
||||
"commitment": string(CommitmentMax),
|
||||
|
@ -799,7 +806,7 @@ func TestClient_GetBlockTime(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetClusterNodes(t *testing.T) {
|
||||
responseBody := `[{"featureSet":743297851,"gossip":"162.55.111.250:8001","pubkey":"DMeohMfD3JzmYZA34jL9iiTXp5N7tpAR3rAoXMygdH3U","rpc":null,"shredVersion":18122,"tpu":"162.55.111.250:8004","version":"1.7.3"},{"featureSet":743297851,"gossip":"136.243.131.82:8000","pubkey":"59TSbYfnbb4zx4xf54ApjE8fJRhwzTiSjh9vdHfgyg1U","rpc":"136.243.131.82:8899","shredVersion":18122,"tpu":"136.243.131.82:8003","version":"1.7.3"},{"featureSet":743297851,"gossip":"135.181.114.15:8001","pubkey":"7vu7Q2d4uu9V4xnySHXieeyWvoNh37321kqTd2ATuoj6","rpc":null,"shredVersion":18122,"tpu":null,"version":"1.7.3"}]`
|
||||
responseBody := `[{"featureSet":743297851,"gossip":"162.55.111.250:8001","pubkey":"DMeohMfD3JzmYZA34jL9iiTXp5N7tpAR3rAoXMygdH3U","rpc":"135.181.114.15:8005","shredVersion":18122,"tpu":"162.55.111.250:8004","version":"1.7.3"},{"featureSet":743297851,"gossip":"136.243.131.82:8000","pubkey":"59TSbYfnbb4zx4xf54ApjE8fJRhwzTiSjh9vdHfgyg1U","rpc":"136.243.131.82:8899","shredVersion":18122,"tpu":"136.243.131.82:8003","version":"1.7.3"},{"featureSet":743297851,"gossip":"135.181.114.15:8001","pubkey":"7vu7Q2d4uu9V4xnySHXieeyWvoNh37321kqTd2ATuoj6","rpc":"135.181.114.15:8005","shredVersion":18122,"tpu":"135.181.114.15:8006","version":"1.7.3"}]`
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
|
||||
defer closer()
|
||||
client := New(server.URL)
|
||||
|
@ -2040,7 +2047,7 @@ func TestClient_GetTransaction(t *testing.T) {
|
|||
tx := "KBVcTWwgEhVzwywtunhAXRKjXYYEdPcSCpuEkg484tiE3dFGzHDu9LKKH23uBMdfYt3JCPHeaVeDTZWecboyTrd"
|
||||
|
||||
opts := GetTransactionOpts{
|
||||
Encoding: solana.EncodingJSON,
|
||||
Encoding: solana.EncodingBase64,
|
||||
Commitment: CommitmentMax,
|
||||
}
|
||||
out, err := client.GetTransaction(
|
||||
|
@ -2058,7 +2065,7 @@ func TestClient_GetTransaction(t *testing.T) {
|
|||
"params": []interface{}{
|
||||
tx,
|
||||
map[string]interface{}{
|
||||
"encoding": string(solana.EncodingJSON),
|
||||
"encoding": string(solana.EncodingBase64),
|
||||
"commitment": string(CommitmentMax),
|
||||
},
|
||||
},
|
||||
|
@ -2594,3 +2601,98 @@ func TestClient_IsBlockhashValid(t *testing.T) {
|
|||
func TestClient_SimulateTransaction(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestClient_GetFeeForMessage(t *testing.T) {
|
||||
responseBody := `{"context":{"slot":5068},"value":5000}`
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
|
||||
defer closer()
|
||||
client := New(server.URL)
|
||||
|
||||
out, err := client.GetFeeForMessage(
|
||||
context.Background(),
|
||||
"AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA",
|
||||
CommitmentProcessed,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t,
|
||||
map[string]interface{}{
|
||||
"id": float64(0),
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getFeeForMessage",
|
||||
"params": []interface{}{
|
||||
"AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA",
|
||||
map[string]interface{}{
|
||||
"commitment": string(CommitmentProcessed),
|
||||
},
|
||||
},
|
||||
},
|
||||
server.RequestBody(t),
|
||||
)
|
||||
|
||||
expected := mustJSONToInterface([]byte(responseBody))
|
||||
|
||||
got := mustJSONToInterface(mustAnyToJSON(out))
|
||||
|
||||
assert.Equal(t, expected, got, "both deserialized values must be equal")
|
||||
}
|
||||
|
||||
func TestClient_GetHighestSnapshotSlot(t *testing.T) {
|
||||
responseBody := `{"full":100,"incremental":110}`
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
|
||||
defer closer()
|
||||
client := New(server.URL)
|
||||
|
||||
out, err := client.GetHighestSnapshotSlot(
|
||||
context.Background(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t,
|
||||
map[string]interface{}{
|
||||
"id": float64(0),
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getHighestSnapshotSlot",
|
||||
},
|
||||
server.RequestBody(t),
|
||||
)
|
||||
|
||||
expected := mustJSONToInterface([]byte(responseBody))
|
||||
|
||||
got := mustJSONToInterface(mustAnyToJSON(out))
|
||||
|
||||
assert.Equal(t, expected, got, "both deserialized values must be equal")
|
||||
}
|
||||
|
||||
func TestClient_GetLatestBlockhash(t *testing.T) {
|
||||
responseBody := `{"context":{"slot":2792},"value":{"blockhash":"EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N","lastValidBlockHeight":3090}}`
|
||||
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
|
||||
defer closer()
|
||||
client := New(server.URL)
|
||||
|
||||
out, err := client.GetLatestBlockhash(
|
||||
context.Background(),
|
||||
CommitmentProcessed,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t,
|
||||
map[string]interface{}{
|
||||
"id": float64(0),
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getLatestBlockhash",
|
||||
"params": []interface{}{
|
||||
map[string]interface{}{
|
||||
"commitment": string(CommitmentProcessed),
|
||||
},
|
||||
},
|
||||
},
|
||||
server.RequestBody(t),
|
||||
)
|
||||
|
||||
expected := mustJSONToInterface([]byte(responseBody))
|
||||
|
||||
got := mustJSONToInterface(mustAnyToJSON(out))
|
||||
|
||||
assert.Equal(t, expected, got, "both deserialized values must be equal")
|
||||
}
|
||||
|
|
|
@ -200,10 +200,11 @@ func (cl *Client) GetConfirmedTransactionWithOpts(
|
|||
if !solana.IsAnyOfEncodingType(
|
||||
opts.Encoding,
|
||||
// Valid encodings:
|
||||
solana.EncodingJSON,
|
||||
// solana.EncodingJSON, // TODO
|
||||
// solana.EncodingJSONParsed, // TODO
|
||||
solana.EncodingBase58,
|
||||
solana.EncodingBase64,
|
||||
solana.EncodingBase64Zstd,
|
||||
) {
|
||||
return nil, fmt.Errorf("provided encoding is not supported: %s", opts.Encoding)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetFeeForMessage(
|
||||
context.Background(),
|
||||
"AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA",
|
||||
rpc.CommitmentProcessed,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetHighestSnapshotSlot(
|
||||
context.Background(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := rpc.TestNet_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
example, err := client.GetLatestBlockhash(
|
||||
context.Background(),
|
||||
rpc.CommitmentFinalized,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spew.Dump(example)
|
||||
}
|
|
@ -17,6 +17,7 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
|
@ -26,7 +27,7 @@ func main() {
|
|||
endpoint := rpc.MainNetBeta_RPC
|
||||
client := rpc.New(endpoint)
|
||||
|
||||
blockHash := solana.MustHashFromBase58("krakeNd6ednDPEXxHAmoBs1qKVM8kLg79PvWF2mhXV1")
|
||||
blockHash := solana.MustHashFromBase58("J7rBdM6AecPDEZp8aPq5iPSNKVkU5Q76F3oAV4eW5wsW")
|
||||
out, err := client.IsBlockhashValid(
|
||||
context.TODO(),
|
||||
blockHash,
|
||||
|
|
|
@ -60,9 +60,6 @@ type GetBlockOpts struct {
|
|||
}
|
||||
|
||||
// GetBlock returns identity and transaction information about a confirmed block in the ledger.
|
||||
//
|
||||
// NEW: This method is only available in solana-core v1.7 or newer.
|
||||
// Please use `getConfirmedBlock` for solana-core v1.6
|
||||
func (cl *Client) GetBlock(
|
||||
ctx context.Context,
|
||||
slot uint64,
|
||||
|
@ -85,7 +82,7 @@ func (cl *Client) GetBlockWithOpts(
|
|||
) (out *GetBlockResult, err error) {
|
||||
|
||||
obj := M{
|
||||
"encoding": solana.EncodingJSON,
|
||||
"encoding": solana.EncodingBase64,
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
|
@ -102,10 +99,11 @@ func (cl *Client) GetBlockWithOpts(
|
|||
if !solana.IsAnyOfEncodingType(
|
||||
opts.Encoding,
|
||||
// Valid encodings:
|
||||
solana.EncodingJSON,
|
||||
solana.EncodingJSONParsed,
|
||||
// solana.EncodingJSON, // TODO
|
||||
// solana.EncodingJSONParsed, // TODO
|
||||
solana.EncodingBase58,
|
||||
solana.EncodingBase64,
|
||||
solana.EncodingBase64Zstd,
|
||||
) {
|
||||
return nil, fmt.Errorf("provided encoding is not supported: %s", opts.Encoding)
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@ import (
|
|||
// The result will be an array of u64 integers listing confirmed blocks
|
||||
// between start_slot and either end_slot, if provided, or latest
|
||||
// confirmed block, inclusive. Max range allowed is 500,000 slots.
|
||||
//
|
||||
// NEW: This method is only available in solana-core v1.7 or newer.
|
||||
// Please use `getConfirmedBlocks` for solana-core v1.6.
|
||||
func (cl *Client) GetBlocks(
|
||||
ctx context.Context,
|
||||
startSlot uint64,
|
||||
|
|
|
@ -21,9 +21,6 @@ import (
|
|||
// GetBlocksWithLimit returns a list of confirmed blocks starting at the given slot.
|
||||
// The result field will be an array of u64 integers listing
|
||||
// confirmed blocks starting at startSlot for up to limit blocks, inclusive.
|
||||
//
|
||||
// NEW: This method is only available in solana-core v1.7 or newer.
|
||||
// Please use getConfirmedBlocksWithLimit for solana-core v1.6
|
||||
func (cl *Client) GetBlocksWithLimit(
|
||||
ctx context.Context,
|
||||
startSlot uint64,
|
||||
|
|
|
@ -30,24 +30,24 @@ type GetClusterNodesResult struct {
|
|||
// Node public key.
|
||||
Pubkey solana.PublicKey `json:"pubkey"`
|
||||
|
||||
// Gossip network address for the node.
|
||||
Gossip *string `json:"gossip"`
|
||||
|
||||
// TPU network address for the node.
|
||||
TPU *string `json:"tpu"`
|
||||
|
||||
// TODO: "" or nil ?
|
||||
|
||||
// Gossip network address for the node.
|
||||
Gossip *string `json:"gossip,omitempty"`
|
||||
|
||||
// TPU network address for the node.
|
||||
TPU *string `json:"tpu,omitempty"`
|
||||
|
||||
// JSON RPC network address for the node, or empty if the JSON RPC service is not enabled.
|
||||
RPC *string `json:"rpc"`
|
||||
RPC *string `json:"rpc,omitempty"`
|
||||
|
||||
// The software version of the node, or empty if the version information is not available.
|
||||
Version *string `json:"version"`
|
||||
Version *string `json:"version,omitempty"`
|
||||
|
||||
// TODO: what type is this?
|
||||
// The unique identifier of the node's feature set.
|
||||
FeatureSet int64 `json:"featureSet"`
|
||||
FeatureSet uint32 `json:"featureSet,omitempty"`
|
||||
|
||||
// The shred version the node has been configured to use.
|
||||
ShredVersion int64 `json:"shredVersion"`
|
||||
ShredVersion uint16 `json:"shredVersion,omitempty"`
|
||||
}
|
||||
|
|
|
@ -47,5 +47,5 @@ type GetEpochInfoResult struct {
|
|||
// The number of slots in this epoch.
|
||||
SlotsInEpoch uint64 `json:"slotsInEpoch"`
|
||||
|
||||
TransactionCount uint64 `json:"transactionCount"`
|
||||
TransactionCount *uint64 `json:"transactionCount,omitempty"`
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import (
|
|||
|
||||
// GetFeeCalculatorForBlockhash returns the fee calculator
|
||||
// associated with the query blockhash, or null if the blockhash has expired.
|
||||
//
|
||||
// NOTE: DEPRECATED
|
||||
func (cl *Client) GetFeeCalculatorForBlockhash(
|
||||
ctx context.Context,
|
||||
hash solana.Hash, // query blockhash
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2022 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 rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Get the fee the network will charge for a particular Message.
|
||||
//
|
||||
// **NEW**: This method is only available in solana-core v1.9 or newer. Please use
|
||||
// `getFees` for solana-core v1.8.
|
||||
func (cl *Client) GetFeeForMessage(
|
||||
ctx context.Context,
|
||||
message string, // Base-64 encoded Message
|
||||
commitment CommitmentType, // optional
|
||||
) (out *GetFeeForMessageResult, err error) {
|
||||
params := []interface{}{message}
|
||||
if commitment != "" {
|
||||
params = append(params, M{"commitment": commitment})
|
||||
}
|
||||
err = cl.rpcClient.CallForInto(ctx, &out, "getFeeForMessage", params)
|
||||
return
|
||||
}
|
||||
|
||||
type GetFeeForMessageResult struct {
|
||||
RPCContext
|
||||
|
||||
// Fee corresponding to the message at the specified blockhash.
|
||||
Value *uint64 `json:"value"`
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// 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 rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Returns the highest slot information that the node has snapshots for.
|
||||
// This will find the highest full snapshot slot, and the highest incremental
|
||||
// snapshot slot _based on_ the full snapshot slot, if there is one.
|
||||
//
|
||||
// **NEW: This method is only available in solana-core v1.9 or newer. Please use
|
||||
// `getSnapshotSlot` for solana-core v1.8**
|
||||
func (cl *Client) GetHighestSnapshotSlot(ctx context.Context) (out *GetHighestSnapshotSlotResult, err error) {
|
||||
err = cl.rpcClient.CallForInto(ctx, &out, "getHighestSnapshotSlot", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type GetHighestSnapshotSlotResult struct {
|
||||
Full uint64 `json:"full"` // Highest full snapshot slot.
|
||||
Incremental *uint64 `json:"incremental,omitempty"` // Highest incremental snapshot slot based on full.
|
||||
}
|
|
@ -28,7 +28,7 @@ type GetInflationRewardOpts struct {
|
|||
Epoch *uint64
|
||||
}
|
||||
|
||||
// GetInflationReward returns the inflation reward for a list of addresses for an epoch.
|
||||
// GetInflationReward returns the inflation / staking reward for a list of addresses for an epoch.
|
||||
func (cl *Client) GetInflationReward(
|
||||
ctx context.Context,
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2021 github.com/gagliardetto
|
||||
// This file has been modified by github.com/gagliardetto
|
||||
//
|
||||
// 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 rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gagliardetto/solana-go"
|
||||
)
|
||||
|
||||
// Returns the latest blockhash.
|
||||
//
|
||||
// **NEW: This method is only available in solana-core v1.9 or newer. Please use
|
||||
// `getRecentBlockhash` for solana-core v1.8**
|
||||
func (cl *Client) GetLatestBlockhash(
|
||||
ctx context.Context,
|
||||
commitment CommitmentType, // optional
|
||||
) (out *GetLatestBlockhashResult, err error) {
|
||||
params := []interface{}{}
|
||||
if commitment != "" {
|
||||
params = append(params, M{"commitment": commitment})
|
||||
}
|
||||
|
||||
err = cl.rpcClient.CallForInto(ctx, &out, "getLatestBlockhash", params)
|
||||
return
|
||||
}
|
||||
|
||||
type GetLatestBlockhashResult struct {
|
||||
RPCContext
|
||||
Value *LatestBlockhashResult `json:"value"`
|
||||
}
|
||||
|
||||
type LatestBlockhashResult struct {
|
||||
Blockhash solana.Hash `json:"blockhash"`
|
||||
LastValidBlockHeight uint64 `json:"lastValidBlockHeight"` // Slot.
|
||||
}
|
|
@ -20,7 +20,7 @@ import (
|
|||
"context"
|
||||
)
|
||||
|
||||
// GetSlot returns the current slot the node is processing.
|
||||
// GetSlot returns the slot that has reached the given or default commitment level.
|
||||
func (cl *Client) GetSlot(
|
||||
ctx context.Context,
|
||||
commitment CommitmentType, // optional
|
||||
|
|
|
@ -47,7 +47,7 @@ func (cl *Client) GetSupplyWithOpts(
|
|||
type GetSupplyOpts struct {
|
||||
Commitment CommitmentType `json:"commitment,omitempty"`
|
||||
|
||||
ExcludeNonCirculatingAccountsList bool `json:"excludeNonCirculatingAccountsList,omitempty"`
|
||||
ExcludeNonCirculatingAccountsList bool `json:"excludeNonCirculatingAccountsList,omitempty"` // exclude non circulating accounts list from response
|
||||
}
|
||||
|
||||
type GetSupplyResult struct {
|
||||
|
@ -66,5 +66,6 @@ type SupplyResult struct {
|
|||
NonCirculating uint64 `json:"nonCirculating"`
|
||||
|
||||
// An array of account addresses of non-circulating accounts.
|
||||
// If `excludeNonCirculatingAccountsList` is enabled, the returned array will be empty.
|
||||
NonCirculatingAccounts []solana.PublicKey `json:"nonCirculatingAccounts"`
|
||||
}
|
||||
|
|
|
@ -45,10 +45,11 @@ func (cl *Client) GetTransaction(
|
|||
if !solana.IsAnyOfEncodingType(
|
||||
opts.Encoding,
|
||||
// Valid encodings:
|
||||
solana.EncodingJSON,
|
||||
// solana.EncodingJSON, // TODO
|
||||
// solana.EncodingJSONParsed, // TODO
|
||||
solana.EncodingBase58,
|
||||
solana.EncodingBase64,
|
||||
solana.EncodingBase64Zstd,
|
||||
) {
|
||||
return nil, fmt.Errorf("provided encoding is not supported: %s", opts.Encoding)
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gagliardetto/solana-go"
|
||||
)
|
||||
|
||||
// IsBlockhashValid returns the balance of the account of provided publicKey.
|
||||
// Returns whether a blockhash is still valid or not
|
||||
//
|
||||
// NEW: This method is only available in solana-core v1.9 or newer. Please use getFeeCalculatorForBlockhash for solana-core v1.8
|
||||
// **NEW: This method is only available in solana-core v1.9 or newer. Please use
|
||||
// `getFeeCalculatorForBlockhash` for solana-core v1.8**
|
||||
func (cl *Client) IsBlockhashValid(
|
||||
ctx context.Context,
|
||||
// Blockhash to be queried. Required.
|
||||
|
|
44
rpc/types.go
44
rpc/types.go
|
@ -18,9 +18,11 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
stdjson "encoding/json"
|
||||
"fmt"
|
||||
|
||||
bin "github.com/gagliardetto/binary"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
)
|
||||
|
||||
|
@ -92,9 +94,26 @@ const (
|
|||
)
|
||||
|
||||
type TransactionWithMeta struct {
|
||||
Transaction *DataBytesOrJSON `json:"transaction"`
|
||||
// Transaction status metadata object
|
||||
Meta *TransactionMeta `json:"meta,omitempty"`
|
||||
Transaction *solana.Transaction `json:"transaction"`
|
||||
Meta *TransactionMeta `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
func (twm TransactionWithMeta) MustGetTransaction() *solana.Transaction {
|
||||
tx, err := twm.GetTransaction()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tx
|
||||
}
|
||||
|
||||
func (twm TransactionWithMeta) GetTransaction() (*solana.Transaction, error) {
|
||||
tx := new(solana.Transaction)
|
||||
err := tx.UnmarshalWithDecoder(bin.NewBinDecoder(twm.Transaction.GetBinary()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
type TransactionParsed struct {
|
||||
|
@ -106,6 +125,9 @@ type TokenBalance struct {
|
|||
// Index of the account in which the token balance is provided for.
|
||||
AccountIndex uint16 `json:"accountIndex"`
|
||||
|
||||
// Pubkey of token balance's owner.
|
||||
Owner *solana.PublicKey `json:"owner,omitempty"`
|
||||
|
||||
// Pubkey of the token's mint.
|
||||
Mint solana.PublicKey `json:"mint"`
|
||||
UiTokenAmount *UiTokenAmount `json:"uiTokenAmount"`
|
||||
|
@ -202,7 +224,7 @@ type GetAccountInfoResult struct {
|
|||
|
||||
type IsValidBlockhashResult struct {
|
||||
RPCContext
|
||||
Value bool `json:"value"`
|
||||
Value bool `json:"value"` // True if the blockhash is still valid.
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
|
@ -228,6 +250,20 @@ type DataBytesOrJSON struct {
|
|||
asJSON stdjson.RawMessage
|
||||
}
|
||||
|
||||
func DataBytesOrJSONFromBase64(stringBase64 string) (*DataBytesOrJSON, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(stringBase64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DataBytesOrJSON{
|
||||
rawDataEncoding: solana.EncodingBase64,
|
||||
asDecodedBinary: solana.Data{
|
||||
Encoding: solana.EncodingBase64,
|
||||
Content: decoded,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (dt DataBytesOrJSON) MarshalJSON() ([]byte, error) {
|
||||
if dt.rawDataEncoding == solana.EncodingJSONParsed || dt.rawDataEncoding == solana.EncodingJSON {
|
||||
return json.Marshal(dt.asJSON)
|
||||
|
@ -346,7 +382,7 @@ const (
|
|||
// - This confirmation level also upholds "optimistic confirmation" guarantees in release 1.3 and onwards.
|
||||
CommitmentConfirmed CommitmentType = "confirmed"
|
||||
|
||||
// The node will query its most recent block. Note that the block may not be complete.
|
||||
// The node will query its most recent block. Note that the block may still be skipped by the cluster.
|
||||
CommitmentProcessed CommitmentType = "processed"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright 2022 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 ws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
)
|
||||
|
||||
type BlockResult struct {
|
||||
Context struct {
|
||||
Slot uint64
|
||||
} `json:"context"`
|
||||
Value struct {
|
||||
Slot uint64 `json:"slot"`
|
||||
Err interface{} `json:"err,omitempty"`
|
||||
Block *rpc.GetBlockResult `json:"block,omitempty"`
|
||||
} `json:"value"`
|
||||
}
|
||||
|
||||
type BlockSubscribeFilter interface {
|
||||
isBlockSubscribeFilter()
|
||||
}
|
||||
|
||||
var _ BlockSubscribeFilter = BlockSubscribeFilterAll("")
|
||||
|
||||
type BlockSubscribeFilterAll string
|
||||
|
||||
func (_ BlockSubscribeFilterAll) isBlockSubscribeFilter() {}
|
||||
|
||||
type BlockSubscribeFilterMentionsAccountOrProgram struct {
|
||||
Pubkey solana.PublicKey `json:"pubkey"`
|
||||
}
|
||||
|
||||
func (_ BlockSubscribeFilterMentionsAccountOrProgram) isBlockSubscribeFilter() {}
|
||||
|
||||
func NewBlockSubscribeFilterAll() BlockSubscribeFilter {
|
||||
return BlockSubscribeFilterAll("")
|
||||
}
|
||||
|
||||
func NewBlockSubscribeFilterMentionsAccountOrProgram(pubkey solana.PublicKey) *BlockSubscribeFilterMentionsAccountOrProgram {
|
||||
return &BlockSubscribeFilterMentionsAccountOrProgram{
|
||||
Pubkey: pubkey,
|
||||
}
|
||||
}
|
||||
|
||||
type BlockSubscribeOpts struct {
|
||||
Commitment rpc.CommitmentType
|
||||
Encoding solana.EncodingType `json:"encoding,omitempty"`
|
||||
|
||||
// Level of transaction detail to return.
|
||||
TransactionDetails rpc.TransactionDetailsType
|
||||
|
||||
// Whether to populate the rewards array. If parameter not provided, the default includes rewards.
|
||||
Rewards *bool
|
||||
}
|
||||
|
||||
// NOTE: Unstable, disabled by default
|
||||
//
|
||||
// Subscribe to receive notification anytime a new block is Confirmed or Finalized.
|
||||
//
|
||||
// **This subscription is unstable and only available if the validator was started
|
||||
// with the `--rpc-pubsub-enable-block-subscription` flag. The format of this
|
||||
// subscription may change in the future**
|
||||
func (cl *Client) BlockSubscribe(
|
||||
filter BlockSubscribeFilter,
|
||||
opts *BlockSubscribeOpts,
|
||||
) (*BlockSubscription, error) {
|
||||
var params []interface{}
|
||||
if filter != nil {
|
||||
switch v := filter.(type) {
|
||||
case BlockSubscribeFilterAll:
|
||||
params = append(params, rpc.M{
|
||||
"filter": "all",
|
||||
})
|
||||
case *BlockSubscribeFilterMentionsAccountOrProgram:
|
||||
params = append(params, rpc.M{
|
||||
"filter": rpc.M{
|
||||
"mentionsAccountOrProgram": v.Pubkey,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
if opts != nil {
|
||||
obj := make(rpc.M)
|
||||
if opts.Commitment != "" {
|
||||
obj["commitment"] = opts.Commitment
|
||||
}
|
||||
if opts.Encoding != "" {
|
||||
if !solana.IsAnyOfEncodingType(
|
||||
opts.Encoding,
|
||||
// Valid encodings:
|
||||
// solana.EncodingJSON, // TODO
|
||||
// solana.EncodingJSONParsed, // TODO
|
||||
solana.EncodingBase58,
|
||||
solana.EncodingBase64,
|
||||
solana.EncodingBase64Zstd,
|
||||
) {
|
||||
return nil, fmt.Errorf("provided encoding is not supported: %s", opts.Encoding)
|
||||
}
|
||||
obj["encoding"] = opts.Encoding
|
||||
}
|
||||
if opts.TransactionDetails != "" {
|
||||
obj["transactionDetails"] = opts.TransactionDetails
|
||||
}
|
||||
if opts.Rewards != nil {
|
||||
obj["rewards"] = opts.Rewards
|
||||
}
|
||||
if len(obj) > 0 {
|
||||
params = append(params, obj)
|
||||
}
|
||||
}
|
||||
genSub, err := cl.subscribe(
|
||||
params,
|
||||
nil,
|
||||
"blockSubscribe",
|
||||
"blockUnsubscribe",
|
||||
func(msg []byte) (interface{}, error) {
|
||||
var res BlockResult
|
||||
err := decodeResponseFromMessage(msg, &res)
|
||||
return &res, err
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockSubscription{
|
||||
sub: genSub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type BlockSubscription struct {
|
||||
sub *Subscription
|
||||
}
|
||||
|
||||
func (sw *BlockSubscription) Recv() (*BlockResult, error) {
|
||||
select {
|
||||
case d := <-sw.sub.stream:
|
||||
return d.(*BlockResult), nil
|
||||
case err := <-sw.sub.err:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (sw *BlockSubscription) Unsubscribe() {
|
||||
sw.sub.Unsubscribe()
|
||||
}
|
|
@ -19,6 +19,7 @@ package solana
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
@ -74,9 +75,6 @@ type CompiledInstruction struct {
|
|||
// and that can be an issue.
|
||||
ProgramIDIndex uint16 `json:"programIdIndex"`
|
||||
|
||||
AccountCount bin.Varuint16 `json:"-" bin:"sizeof=Accounts"`
|
||||
DataLength bin.Varuint16 `json:"-" bin:"sizeof=Data"`
|
||||
|
||||
// List of ordered indices into the message.accountKeys array indicating which accounts to pass to the program.
|
||||
// NOTE: it is actually a []uint8, but using a uint16 because []uint8 is treated as a []byte everywhere,
|
||||
// and that can be an issue.
|
||||
|
@ -315,9 +313,7 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
|
|||
}
|
||||
message.Instructions = append(message.Instructions, CompiledInstruction{
|
||||
ProgramIDIndex: accountKeyIndex[instruction.ProgramID().String()],
|
||||
AccountCount: bin.Varuint16(uint16(len(accountIndex))),
|
||||
Accounts: accountIndex,
|
||||
DataLength: bin.Varuint16(uint16(len(data))),
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
@ -425,6 +421,22 @@ func (tx *Transaction) String() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
func (tx Transaction) ToBase64() (string, error) {
|
||||
out, err := tx.MarshalBinary()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(out), nil
|
||||
}
|
||||
|
||||
func (tx Transaction) MustToBase64() string {
|
||||
out, err := tx.ToBase64()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (tx *Transaction) EncodeToTree(parent treeout.Branches) {
|
||||
|
||||
parent.ParentFunc(func(txTree treeout.Branches) {
|
||||
|
|
|
@ -96,16 +96,12 @@ func TestNewTransaction(t *testing.T) {
|
|||
assert.Equal(t, trx.Message.Instructions, []CompiledInstruction{
|
||||
{
|
||||
ProgramIDIndex: 5,
|
||||
AccountCount: 2,
|
||||
Accounts: []uint16{0, 01},
|
||||
DataLength: 2,
|
||||
Data: []byte{0xaa, 0xbb},
|
||||
},
|
||||
{
|
||||
ProgramIDIndex: 6,
|
||||
AccountCount: 4,
|
||||
Accounts: []uint16{4, 3, 1, 2},
|
||||
DataLength: 2,
|
||||
Data: []byte{0xcc, 0xdd},
|
||||
},
|
||||
})
|
||||
|
@ -155,8 +151,6 @@ func TestTransactionDecode(t *testing.T) {
|
|||
[]CompiledInstruction{
|
||||
{
|
||||
ProgramIDIndex: 2,
|
||||
AccountCount: 2,
|
||||
DataLength: 12,
|
||||
Accounts: []uint16{
|
||||
0,
|
||||
1,
|
||||
|
|
|
@ -31,14 +31,12 @@ func TestCompiledInstructions(t *testing.T) {
|
|||
|
||||
ci := &CompiledInstruction{
|
||||
ProgramIDIndex: 5,
|
||||
AccountCount: 3,
|
||||
Accounts: []uint16{2, 5, 8},
|
||||
DataLength: 5,
|
||||
Data: Base58([]byte{1, 2, 3, 4, 5}),
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
encoder := bin.NewBinEncoder(buf)
|
||||
err := encoder.Encode(ci)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0x5, 0x0, 0x3, 0x5, 0x2, 0x0, 0x5, 0x0, 0x8, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5}, buf.Bytes())
|
||||
assert.Equal(t, []byte{0x5, 0x0, 0x3, 0x2, 0x0, 0x5, 0x0, 0x8, 0x0, 0x5, 0x1, 0x2, 0x3, 0x4, 0x5}, buf.Bytes())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue