Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TA-3947]: add ledger_entry request #95

Draft
wants to merge 8 commits into
base: v0.1.x
Choose a base branch
from
Draft
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

#### xrpl

- Added `LedgerEntry` query.

## [v0.1.3]

### Added

- Added `APIVersion` field to the `Client` struct.
Expand Down
65 changes: 65 additions & 0 deletions xrpl/queries/ledger/ledger_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ledger

import (
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
"github.com/Peersyst/xrpl-go/xrpl/queries/ledger/types"
"github.com/Peersyst/xrpl-go/xrpl/queries/version"
)

// ############################################################################
// Request
// ############################################################################

// The `ledger_entry` method returns a single ledger object from the XRP Ledger
// in its raw format. Expects a response in the form of a EntryResponse.
type EntryRequest struct {
common.BaseRequest
MPTIssuance bool `json:"mpt_issuance,omitempty"`
MPToken interface{} `json:"mptoken,omitempty"`
AMM types.EntryAssetPair `json:"amm,omitempty"`
IncludeDeleted bool `json:"include_deleted,omitempty"`
Binary bool `json:"binary,omitempty"`
Index string `json:"index,omitempty"`
AccountRoot string `json:"account_root,omitempty"`
Check string `json:"check,omitempty"`
Credential interface{} `json:"credential,omitempty"`
DepositPreauth interface{} `json:"deposit_preauth,omitempty"`
Did string `json:"did,omitempty"`
Directory interface{} `json:"directory,omitempty"`
Escrow interface{} `json:"escrow,omitempty"`
Offer interface{} `json:"offer,omitempty"`
PaymentChannel string `json:"payment_channel,omitempty"`
RippleState types.EntryRippleState `json:"ripple_state,omitempty"`
Ticket interface{} `json:"ticket,omitempty"`
NFTPage string `json:"nft_page,omitempty"`
BridgeAccount string `json:"bridge_account,omitempty"`
Bridge types.EntryXChainBridge `json:"bridge,omitempty"`
XChainOwnedClaimID interface{} `json:"xchain_owned_claim_id,omitempty"`
XChainOwnedCreateAccountClaimID interface{} `json:"xchain_owned_create_account_claim_id,omitempty"`
}

func (e *EntryRequest) Method() string {
return "ledger_entry"
}

func (e *EntryRequest) APIVersion() int {
return version.RippledAPIV2
}

func (e *EntryRequest) Validate() error {
return nil
}

// ############################################################################
// Response
// ############################################################################

// The expected response from the ledger_entry method.
type EntryResponse struct {
Index string `json:"index"`
LedgerCurrentIndex common.LedgerIndex `json:"ledger_current_index"`
Node interface{} `json:"node,omitempty"`
NodeBinary string `json:"node_binary,omitempty"`
Validated bool `json:"validated,omitempty"`
DeletedLedgerIndex common.LedgerIndex `json:"deleted_ledger_index,omitempty"`
}
78 changes: 78 additions & 0 deletions xrpl/queries/ledger/ledger_entry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package ledger

import (
"testing"

"github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types"
types "github.com/Peersyst/xrpl-go/xrpl/queries/ledger/types"
"github.com/Peersyst/xrpl-go/xrpl/testutil"
)

func TestLedgerEntryRequest(t *testing.T) {
s := EntryRequest{
MPTIssuance: true,
Binary: true,
Index: "some_index",
AccountRoot: "some_account",
Check: "some_check",
Did: "some_did",
PaymentChannel: "some_channel",
NFTPage: "some_nft_page",
BridgeAccount: "some_bridge_account",
Bridge: types.EntryXChainBridge{
LockingChainDoor: "door",
LockingChainIssue: "issue",
IssuingChainDoor: "door2",
IssuingChainIssue: "issue2",
},
IncludeDeleted: true,
AMM: types.EntryAssetPair{
Asset: ledger.Asset{
Currency: "XRP",
},
Asset2: ledger.Asset{
Currency: "USD",
},
},
RippleState: types.EntryRippleState{
Accounts: []string{"acc1", "acc2"},
Currency: "XRP",
},
}
j := `{
"mpt_issuance": true,
"amm": {
"asset": {
"currency": "XRP"
},
"asset2": {
"currency": "USD"
}
},
"include_deleted": true,
"binary": true,
"index": "some_index",
"account_root": "some_account",
"check": "some_check",
"did": "some_did",
"payment_channel": "some_channel",
"ripple_state": {
"accounts": [
"acc1",
"acc2"
],
"currency": "XRP"
},
"nft_page": "some_nft_page",
"bridge_account": "some_bridge_account",
"bridge": {
"locking_chain_door": "door",
"locking_chain_issue": "issue",
"issuing_chain_door": "door2",
"issuing_chain_issue": "issue2"
}
}`
if err := testutil.Serialize(t, s, j); err != nil {
t.Error(err)
}
}
69 changes: 69 additions & 0 deletions xrpl/queries/ledger/types/entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package types

import (
"github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types"
)

type EntryAssetPair struct {
Asset ledger.Asset `json:"asset"`
Asset2 ledger.Asset `json:"asset2"`
}

type EntryMPToken struct {
MPTIssuanceID string `json:"mp_issuance_id"`
Account string `json:"account"`
}

type EntryCredential struct {
Subject string `json:"subject"`
Issuer string `json:"issuer"`
CredentialType string `json:"credential_type"`
}

type EntryDepositPreauth struct {
Owner string `json:"owner"`
Authorized string `json:"authorized"`
}

type EntryDirectory struct {
SubIndex uint32 `json:"sub_index,omitempty"`
DirRoot string `json:"dir_root,omitempty"`
Owner string `json:"owner,omitempty"`
}

type EntryEscrow struct {
Owner string `json:"owner"`
Seq string `json:"seq"`
}

type EntryOffer struct {
Account string `json:"account"`
Seq string `json:"seq"`
}

type EntryRippleState struct {
Accounts []string `json:"accounts"`
Currency string `json:"currency"`
}

type EntryTicket struct {
Owner string `json:"owner"`
TicketSequence string `json:"ticket_sequence"`
}

type EntryXChainBridge struct {
LockingChainDoor string `json:"locking_chain_door"`
LockingChainIssue string `json:"locking_chain_issue"`
IssuingChainDoor string `json:"issuing_chain_door"`
IssuingChainIssue string `json:"issuing_chain_issue"`
}

type EntryXChainOwnedClaimID struct {
EntryXChainBridge
XChainOwnedClaimID interface{} `json:"xchain_owned_claim_id"`
}

type EntryXChainOwnedCreateAccountClaimID struct {
EntryXChainBridge
XChainOwnedCreateAccountClaimID interface{} `json:"xchain_owned_create_account_claim_id"`
}
17 changes: 17 additions & 0 deletions xrpl/rpc/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ func (c *Client) GetLedgerIndex() (common.LedgerIndex, error) {
return lr.LedgerIndex, err
}

// GetLedgerEntry retrieves information about a specific ledger entry.
// It takes a LedgerEntryRequest as input and returns a LedgerEntryResponse,
// along with any error encountered.
func (c *Client) GetLedgerEntry(req *ledger.EntryRequest) (*ledger.EntryResponse, error) {
res, err := c.Request(req)
if err != nil {
return nil, err
}

var lr ledger.EntryResponse
err = res.GetResult(&lr)
if err != nil {
return nil, err
}
return &lr, nil
}

// GetClosedLedger retrieves information about the last closed ledger.
// It returns a ClosedResponse containing the ledger information and any error encountered.
func (c *Client) GetClosedLedger() (*ledger.ClosedResponse, error) {
Expand Down
71 changes: 71 additions & 0 deletions xrpl/rpc/queries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,77 @@ func TestClient_GetLedgerIndex(t *testing.T) {
}
}

func TestClient_GetLedgerEntry(t *testing.T) {
tests := []struct {
name string
mockResponse string
mockStatus int
request *ledgerqueries.EntryRequest
expected *ledgerqueries.EntryResponse
expectedError string
}{
{
name: "successful response",
mockResponse: `{
"result": {
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
"ledger_current_index": 61809073,
"node_binary": "test",
"validated": true,
"deleted_ledger_index": 0
}
}`,
mockStatus: 200,
request: &ledgerqueries.EntryRequest{
Index: "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
},
expected: &ledgerqueries.EntryResponse{
Index: "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
LedgerCurrentIndex: 61809073,
NodeBinary: "test",
Validated: true,
DeletedLedgerIndex: 0,
},
},
{
name: "error response",
mockResponse: `{
"result": {
"error": "entryNotFound",
"status": "error"
}
}`,
mockStatus: 200,
request: &ledgerqueries.EntryRequest{},
expectedError: "entryNotFound",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mc := testutil.JSONRPCMockClient{}
mc.DoFunc = testutil.MockResponse(tt.mockResponse, tt.mockStatus, &mc)

cfg, err := NewClientConfig("http://testnode/", WithHTTPClient(&mc))
require.NoError(t, err)

client := NewClient(cfg)

resp, err := client.GetLedgerEntry(tt.request)

if tt.expectedError != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tt.expectedError)
return
}

require.NoError(t, err)
require.Equal(t, tt.expected, resp)
})
}
}


func TestClient_GetClosedLedger(t *testing.T) {
tests := []struct {
name string
Expand Down
16 changes: 16 additions & 0 deletions xrpl/websocket/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,22 @@ func (c *Client) GetLedgerIndex() (common.LedgerIndex, error) {
return lr.LedgerIndex, err
}

// GetLedgerEntry retrieves information about a specific ledger entry.
// It takes a LedgerEntryRequest as input and returns a LedgerEntryResponse,
// along with any error encountered.
func (c *Client) GetLedgerEntry(req *ledger.EntryRequest) (*ledger.EntryResponse, error) {
res, err := c.Request(req)
if err != nil {
return nil, err
}
var lr ledger.EntryResponse
err = res.GetResult(&lr)
if err != nil {
return nil, err
}
return &lr, nil
}

// GetClosedLedger retrieves information about the last closed ledger.
// It returns a ClosedResponse containing the ledger information and any error encountered.
func (c *Client) GetClosedLedger() (*ledger.ClosedResponse, error) {
Expand Down
Loading
Loading