diff --git a/.github/workflows/horizon.yml b/.github/workflows/horizon.yml index 7bf3ac5cdf..704b34dbd7 100644 --- a/.github/workflows/horizon.yml +++ b/.github/workflows/horizon.yml @@ -134,14 +134,27 @@ jobs: # Any range should do for basic testing, this range was chosen pretty early in history so that it only takes a few mins to run run: | chmod 755 ./exp/lighthorizon/build/build.sh - ./exp/lighthorizon/build/build.sh ledgerexporter stellar latest false - docker run -e ARCHIVE_TARGET=file:///ledgerexport-test\ + mkdir $PWD/ledgerexport + mkdir $PWD/index + + ./exp/lighthorizon/build/build.sh all stellar latest false + docker run -e ARCHIVE_TARGET=file:///ledgerexport\ -e START=5\ - -e END=50\ + -e END=150\ -e NETWORK_PASSPHRASE="Test SDF Network ; September 2015"\ -e CAPTIVE_CORE_CONFIG="/captive-core-testnet.cfg"\ -e HISTORY_ARCHIVE_URLS="https://history.stellar.org/prd/core-testnet/core_testnet_001,https://history.stellar.org/prd/core-testnet/core_testnet_002"\ + -v $PWD/ledgerexport:/ledgerexport\ stellar/lighthorizon-ledgerexporter + + # run map job + docker run -e NETWORK_PASSPHRASE='testnet' -e JOB_INDEX_ENV=AWS_BATCH_JOB_ARRAY_INDEX -e AWS_BATCH_JOB_ARRAY_INDEX=0 -e BATCH_SIZE=64 -e FIRST_CHECKPOINT=64 \ + -e WORKER_COUNT=1 -e RUN_MODE=map -v $PWD/ledgerexport:/ledgermeta -e TXMETA_SOURCE=file:///ledgermeta -v $PWD/index:/index -e INDEX_TARGET=file:///index stellar/lighthorizon-index-batch + + # run reduce job + docker run -e NETWORK_PASSPHRASE='testnet' -e JOB_INDEX_ENV=AWS_BATCH_JOB_ARRAY_INDEX -e AWS_BATCH_JOB_ARRAY_INDEX=0 -e MAP_JOB_COUNT=1 -e REDUCE_JOB_COUNT=1 \ + -e WORKER_COUNT=1 -e RUN_MODE=reduce -v $PWD/index:/index -e INDEX_SOURCE_ROOT=file:///index -e INDEX_TARGET=file:///index stellar/lighthorizon-index-batch + # Push images - if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/lighthorizon' name: Login to DockerHub diff --git a/exp/lighthorizon/actions/accounts.go b/exp/lighthorizon/actions/accounts.go index 0db279c999..e1158b3039 100644 --- a/exp/lighthorizon/actions/accounts.go +++ b/exp/lighthorizon/actions/accounts.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/stellar/go/support/log" + "github.com/stellar/go/xdr" "github.com/stellar/go/exp/lighthorizon/adapters" "github.com/stellar/go/exp/lighthorizon/services" @@ -72,9 +73,10 @@ func NewTXByAccountHandler(lightHorizon services.LightHorizon) func(http.Respons return } + encoder := xdr.NewEncodingBuffer() for _, txn := range txns { var response hProtocol.Transaction - response, err = adapters.PopulateTransaction(r, &txn) + response, err = adapters.PopulateTransaction(r.URL, &txn, encoder) if err != nil { log.Error(err) sendErrorResponse(r.Context(), w, supportProblem.ServerError) diff --git a/exp/lighthorizon/adapters/testdata/transactions.json b/exp/lighthorizon/adapters/testdata/transactions.json new file mode 100644 index 0000000000..6128801533 --- /dev/null +++ b/exp/lighthorizon/adapters/testdata/transactions.json @@ -0,0 +1,67 @@ +{ + "_links": { + "self": { + "href": "https://horizon.stellar.org/accounts/GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD/transactions?cursor=179530990183178241\u0026limit=1\u0026order=desc" + }, + "next": { + "href": "https://horizon.stellar.org/accounts/GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD/transactions?cursor=179530990183174144\u0026limit=1\u0026order=desc" + }, + "prev": { + "href": "https://horizon.stellar.org/accounts/GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD/transactions?cursor=179530990183174144\u0026limit=1\u0026order=asc" + } + }, + "_embedded": { + "records": [ + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/transactions/55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd" + }, + "account": { + "href": "https://horizon.stellar.org/accounts/GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD" + }, + "ledger": { + "href": "https://horizon.stellar.org/ledgers/41800316" + }, + "operations": { + "href": "https://horizon.stellar.org/transactions/55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon.stellar.org/transactions/55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=179530990183174144" + }, + "succeeds": { + "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=179530990183174144" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd" + } + }, + "id": "55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd", + "paging_token": "179530990183174144", + "successful": true, + "hash": "55d8aa3693489ffc1d70b8ba33b8b5c012ec098f6f104383e3f090048488febd", + "ledger": 41800316, + "created_at": "2022-07-17T13:08:41Z", + "source_account": "GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD", + "source_account_sequence": "172589382434294350", + "fee_account": "GBFHFINUD6NVGSX33PY25DDRCABN3H2JTDMLUEXAUEJVV22HTXVGLEZD", + "fee_charged": "100", + "max_fee": "100000", + "operation_count": 1, + "envelope_xdr": "AAAAAgAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQABhqACZSkhAAAKTgAAAAAAAAAAAAAAAQAAAAEAAAAASnKhtB+bU0r72/GujHEQAt2fSZjYuhLgoRNa60ed6mUAAAANAAAAAXlYTE0AAAAAIjbXcP4NPgFSGXXVz3rEhCtwldaxqddo0+mmMumZBr4AAAACVAvkAAAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQAAAAJEUklGVAAAAAAAAAAAAAAAvSOzPqUOGnDIcJOm7T85qDFRM0wfOVoubgkEPk95DZ0AAAEQvqAGdQAAAAEAAAAAAAAAAAAAAAFHneplAAAAQAVm9muIrK31Z+m2ZvhDYhtuoHcc/n+MO0DOaiQjfW+tsUNVCOw7foHiDRVLBdAHBZT+xxa3F+Ek9wQiKzxtQQM=", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAANAAAAAAAAAAIAAAABAAAAAPaTW9sBV2ja6yDUtPcpGpUrnVEHaTHC4I065TklIsguAAAAAD1H0goAAAAAAAAAAlQE8wsAAAABeVhMTQAAAAAiNtdw/g0+AVIZddXPesSEK3CV1rGp12jT6aYy6ZkGvgAAAAJUC+QAAAAAAgRnzllf8Sas0MUQlkxROsBgUzEoIN2XrYP9tlH5SINjAAAAAkRSSUZUAAAAAAAAAAAAAAC9I7M+pQ4acMhwk6btPzmoMVEzTB85Wi5uCQQ+T3kNnQAAARN/56NFAAAAAAAAAAJUBPMLAAAAAEpyobQfm1NK+9vxroxxEALdn0mY2LoS4KETWutHneplAAAAAkRSSUZUAAAAAAAAAAAAAAC9I7M+pQ4acMhwk6btPzmoMVEzTB85Wi5uCQQ+T3kNnQAAARN/56NFAAAAAA==", + "result_meta_xdr": "AAAAAgAAAAIAAAADAn3SfAAAAAAAAAAASnKhtB+bU0r72/GujHEQAt2fSZjYuhLgoRNa60ed6mUAAAAAENitnwJlKSEAAApNAAAACgAAAAEAAAAAxHHGQ3BiyVBqiTQuU4oa2kBNL0HPHTolX0Mh98bg4XUAAAAAAAAACWxvYnN0ci5jbwAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAACfdJjAAAAAGLUCUkAAAAAAAAAAQJ90nwAAAAAAAAAAEpyobQfm1NK+9vxroxxEALdn0mY2LoS4KETWutHneplAAAAABDYrZ8CZSkhAAAKTgAAAAoAAAABAAAAAMRxxkNwYslQaok0LlOKGtpATS9Bzx06JV9DIffG4OF1AAAAAAAAAAlsb2JzdHIuY28AAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAAn3SfAAAAABi1AnZAAAAAAAAAAEAAAAMAAAAAwJ90nwAAAAAAAAAAPaTW9sBV2ja6yDUtPcpGpUrnVEHaTHC4I065TklIsguAAAAPP5dpSACFip8AC7CtgAAAAcAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAc2nqv7AAAADbUPYzLAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAAn3SegAAAABi1AnNAAAAAAAAAAECfdJ8AAAAAAAAAAD2k1vbAVdo2usg1LT3KRqVK51RB2kxwuCNOuU5JSLILgAAADqqWLIVAhYqfAAuwrYAAAAHAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAHNp6r+wAAAA0gDiZwAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAJ90noAAAAAYtQJzQAAAAAAAAADAn3SUAAAAAUEZ85ZX/EmrNDFEJZMUTrAYFMxKCDdl62D/bZR+UiDYwAAAAAAAAAAAAAAAkRSSUZUAAAAAAAAAAAAAAC9I7M+pQ4acMhwk6btPzmoMVEzTB85Wi5uCQQ+T3kNnQAAAB4AAAIEaTMNuAAA8H8XoYXHAAAUwrrMCE0AAAAAAAAAaAAAAAAAAAABAn3SfAAAAAUEZ85ZX/EmrNDFEJZMUTrAYFMxKCDdl62D/bZR+UiDYwAAAAAAAAAAAAAAAkRSSUZUAAAAAAAAAAAAAAC9I7M+pQ4acMhwk6btPzmoMVEzTB85Wi5uCQQ+T3kNnQAAAB4AAAIGvTgAwwAA72uXueKCAAAUwrrMCE0AAAAAAAAAaAAAAAAAAAADAn3SYwAAAAEAAAAASnKhtB+bU0r72/GujHEQAt2fSZjYuhLgoRNa60ed6mUAAAACRFJJRlQAAAAAAAAAAAAAAL0jsz6lDhpwyHCTpu0/OagxUTNMHzlaLm4JBD5PeQ2dAAAAAAAAAAB//////////wAAAAEAAAAAAAAAAAAAAAECfdJ8AAAAAQAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQAAAAJEUklGVAAAAAAAAAAAAAAAvSOzPqUOGnDIcJOm7T85qDFRM0wfOVoubgkEPk95DZ0AAAETf+ejRX//////////AAAAAQAAAAAAAAAAAAAAAwJ90nwAAAABAAAAAPaTW9sBV2ja6yDUtPcpGpUrnVEHaTHC4I065TklIsguAAAAAXlYTE0AAAAAIjbXcP4NPgFSGXXVz3rEhCtwldaxqddo0+mmMumZBr4AAAAggUA/Y3//////////AAAAAQAAAAEAAAA21OED/gAAABzamxRcAAAAAAAAAAAAAAABAn3SfAAAAAEAAAAA9pNb2wFXaNrrINS09ykalSudUQdpMcLgjTrlOSUiyC4AAAABeVhMTQAAAAAiNtdw/g0+AVIZddXPesSEK3CV1rGp12jT6aYy6ZkGvgAAACLVTCNjf/////////8AAAABAAAAAQAAADSA1R//AAAAHNqbFFwAAAAAAAAAAAAAAAMCfdJ8AAAAAgAAAAD2k1vbAVdo2usg1LT3KRqVK51RB2kxwuCNOuU5JSLILgAAAAA9R9IKAAAAAAAAAAF5WExNAAAAACI213D+DT4BUhl11c96xIQrcJXWsanXaNPppjLpmQa+AAAANtQ9jMt7hXu5e4QLegAAAAAAAAAAAAAAAAAAAAECfdJ8AAAAAgAAAAD2k1vbAVdo2usg1LT3KRqVK51RB2kxwuCNOuU5JSLILgAAAAA9R9IKAAAAAAAAAAF5WExNAAAAACI213D+DT4BUhl11c96xIQrcJXWsanXaNPppjLpmQa+AAAANIA4mcB7hXu5e4QLegAAAAAAAAAAAAAAAAAAAAMCfcCZAAAAAQAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQAAAAF5WExNAAAAACI213D+DT4BUhl11c96xIQrcJXWsanXaNPppjLpmQa+AAAAEqEyDdl//////////wAAAAEAAAAAAAAAAAAAAAECfdJ8AAAAAQAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQAAAAF5WExNAAAAACI213D+DT4BUhl11c96xIQrcJXWsanXaNPppjLpmQa+AAAAEE0mKdl//////////wAAAAEAAAAAAAAAAAAAAAA=", + "fee_meta_xdr": "AAAAAgAAAAMCfdJjAAAAAAAAAABKcqG0H5tTSvvb8a6McRAC3Z9JmNi6EuChE1rrR53qZQAAAAAQ2K4DAmUpIQAACk0AAAAKAAAAAQAAAADEccZDcGLJUGqJNC5TihraQE0vQc8dOiVfQyH3xuDhdQAAAAAAAAAJbG9ic3RyLmNvAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAJ90mMAAAAAYtQJSQAAAAAAAAABAn3SfAAAAAAAAAAASnKhtB+bU0r72/GujHEQAt2fSZjYuhLgoRNa60ed6mUAAAAAENitnwJlKSEAAApNAAAACgAAAAEAAAAAxHHGQ3BiyVBqiTQuU4oa2kBNL0HPHTolX0Mh98bg4XUAAAAAAAAACWxvYnN0ci5jbwAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAACfdJjAAAAAGLUCUkAAAAA", + "memo_type": "none", + "signatures": [ + "BWb2a4isrfVn6bZm+ENiG26gdxz+f4w7QM5qJCN9b62xQ1UI7Dt+geINFUsF0AcFlP7HFrcX4ST3BCIrPG1BAw==" + ] + } + ] + } +} \ No newline at end of file diff --git a/exp/lighthorizon/adapters/transaction.go b/exp/lighthorizon/adapters/transaction.go index da558ba02b..781e71bd99 100644 --- a/exp/lighthorizon/adapters/transaction.go +++ b/exp/lighthorizon/adapters/transaction.go @@ -1,84 +1,295 @@ package adapters import ( + "bytes" "encoding/base64" + "encoding/hex" "fmt" - "net/http" + "net/url" "strconv" + "strings" "time" + "unicode/utf8" + "github.com/stellar/go/exp/lighthorizon/archive" "github.com/stellar/go/exp/lighthorizon/common" + "github.com/stellar/go/network" protocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/render/hal" + "github.com/stellar/go/xdr" + "golang.org/x/exp/constraints" ) -func PopulateTransaction(r *http.Request, tx *common.Transaction) (protocol.Transaction, error) { - hash, err := tx.TransactionHash() +// PopulateTransaction converts between ingested XDR and RESTful JSON. In +// Horizon Classic, the data goes from Captive Core -> DB -> JSON. In our case, +// there's no DB intermediary, so we need to directly translate. +func PopulateTransaction( + baseUrl *url.URL, + tx *common.Transaction, + encoder *xdr.EncodingBuffer, +) (dest protocol.Transaction, err error) { + txHash, err := tx.TransactionHash() if err != nil { - return protocol.Transaction{}, err + return } - toid := strconv.FormatInt(tx.TOID(), 10) - envelopeXdr, err := tx.TransactionEnvelope.MarshalBinary() + dest.ID = txHash + dest.Successful = tx.Result.Successful() + dest.Hash = txHash + dest.Ledger = int32(tx.LedgerHeader.LedgerSeq) + dest.LedgerCloseTime = time.Unix(int64(tx.LedgerHeader.ScpValue.CloseTime), 0).UTC() + + source := tx.SourceAccount() + dest.Account = source.ToAccountId().Address() + if _, ok := source.GetMed25519(); ok { + dest.AccountMuxed, err = source.GetAddress() + if err != nil { + return + } + dest.AccountMuxedID, err = source.GetId() + if err != nil { + return + } + } + dest.AccountSequence = tx.Envelope.SeqNum() + + envelopeBase64, err := encoder.MarshalBase64(tx.Envelope) + if err != nil { + return + } + resultBase64, err := encoder.MarshalBase64(&tx.Result.Result) + if err != nil { + return + } + metaBase64, err := encoder.MarshalBase64(tx.UnsafeMeta) if err != nil { - return protocol.Transaction{}, err + return } - resultXdr, err := tx.TransactionResult.MarshalBinary() + feeMetaBase64, err := encoder.MarshalBase64(tx.FeeChanges) if err != nil { - return protocol.Transaction{}, err - } - // resultMetaXdr, err := tx.TransactionResultMeta.MarshalBinary() - // if err != nil { - // return protocol.Transaction{}, err - // } - // feeMetaXdr, err := tx.TransactionResult.Me - memo := tx.TransactionEnvelope.Memo() - base := protocol.Transaction{ - ID: hash, - PT: toid, - Successful: tx.TransactionResult.Successful(), - Hash: hash, - Ledger: int32(tx.LedgerHeader.LedgerSeq), - LedgerCloseTime: time.Unix(int64(tx.LedgerHeader.ScpValue.CloseTime), 0).UTC(), - Account: tx.SourceAccount().ToAccountId().Address(), - FeeCharged: int64(tx.TransactionResult.FeeCharged), - OperationCount: int32(len(tx.TransactionEnvelope.Operations())), - EnvelopeXdr: base64.URLEncoding.EncodeToString(envelopeXdr), - ResultXdr: base64.URLEncoding.EncodeToString(resultXdr), - // ResultMetaXdr: string(resultMetaXdr), - // FeeMetaXdr: string(feeMetaXdr), - MemoType: memo.Type.String(), - Memo: memo.GoString(), - } - // TODO: Fill in the rest of the fields - - // timebounds := tx.TransactionEnvelope.TimeBounds() - // if timebounds != nil { - // base.ValidBefore = timeString(&base, &timebounds.MaxTime) - // base.ValidAfter = timeString(&base, &timebounds.MinTime) - // } - - for _, sig := range tx.TransactionEnvelope.Signatures() { - b, err := sig.MarshalBinary() + return + } + + dest.OperationCount = int32(len(tx.Envelope.Operations())) + dest.EnvelopeXdr = envelopeBase64 + dest.ResultXdr = resultBase64 + dest.ResultMetaXdr = metaBase64 + dest.FeeMetaXdr = feeMetaBase64 + dest.MemoType = memoType(*tx.LedgerTransaction) + if m, ok := memo(*tx.LedgerTransaction); ok { + dest.Memo = m + if dest.MemoType == "text" { + var mb string + if mb, err = memoBytes(envelopeBase64); err != nil { + return + } else { + dest.MemoBytes = mb + } + } + } + + dest.Signatures = signatures(tx.Envelope.Signatures()) + + // If we never use this, we'll remove it later. This just defends us against + // nil dereferences. + dest.Preconditions = &protocol.TransactionPreconditions{} + + if tb := tx.Envelope.Preconditions().TimeBounds; tb != nil { + dest.Preconditions.TimeBounds = &protocol.TransactionPreconditionsTimebounds{ + MaxTime: formatTime(tb.MaxTime), + MinTime: formatTime(tb.MinTime), + } + } + + if lb := tx.Envelope.LedgerBounds(); lb != nil { + dest.Preconditions.LedgerBounds = &protocol.TransactionPreconditionsLedgerbounds{ + MinLedger: uint32(lb.MinLedger), + MaxLedger: uint32(lb.MaxLedger), + } + } + + if minSeq := tx.Envelope.MinSeqNum(); minSeq != nil { + dest.Preconditions.MinAccountSequence = fmt.Sprint(*minSeq) + } + + if minSeqAge := tx.Envelope.MinSeqAge(); minSeqAge != nil && *minSeqAge > 0 { + dest.Preconditions.MinAccountSequenceAge = formatTime(*minSeqAge) + } + + if minSeqGap := tx.Envelope.MinSeqLedgerGap(); minSeqGap != nil { + dest.Preconditions.MinAccountSequenceLedgerGap = uint32(*minSeqGap) + } + + if signers := tx.Envelope.ExtraSigners(); len(signers) > 0 { + dest.Preconditions.ExtraSigners = formatSigners(signers) + } + + if tx.Envelope.IsFeeBump() { + innerTx, ok := tx.Envelope.FeeBump.Tx.InnerTx.GetV1() + if !ok { + panic("Failed to parse inner transaction from fee-bump tx.") + } + + var rawInnerHash [32]byte + rawInnerHash, err = network.HashTransaction(innerTx.Tx, tx.NetworkPassphrase) if err != nil { - return protocol.Transaction{}, err + return + } + innerHash := hex.EncodeToString(rawInnerHash[:]) + + feeAccountMuxed := tx.Envelope.FeeBumpAccount() + dest.FeeAccount = feeAccountMuxed.ToAccountId().Address() + if _, ok := feeAccountMuxed.GetMed25519(); ok { + dest.FeeAccountMuxed, err = feeAccountMuxed.GetAddress() + if err != nil { + return + } + dest.FeeAccountMuxedID, err = feeAccountMuxed.GetId() + if err != nil { + return + } + } + + dest.MaxFee = tx.Envelope.FeeBumpFee() + dest.FeeBumpTransaction = &protocol.FeeBumpTransaction{ + Hash: txHash, + Signatures: signatures(tx.Envelope.FeeBumpSignatures()), + } + dest.InnerTransaction = &protocol.InnerTransaction{ + Hash: innerHash, + MaxFee: int64(innerTx.Tx.Fee), + Signatures: signatures(tx.Envelope.Signatures()), } - base.Signatures = append(base.Signatures, base64.URLEncoding.EncodeToString(b)) - } - - // if memo.Type.String() == "text" { - // if memoBytes, err := memoBytes(row.TxEnvelope); err != nil { - // return err - // } else { - // base.MemoBytes = memoBytes - // } - // } - - lb := hal.LinkBuilder{Base: r.URL} - self := fmt.Sprintf("/transactions/%s", hash) - base.Links.Self = lb.Link(self) - base.Links.Succeeds = lb.Linkf("/effects?order=desc&cursor=%s", base.PT) - base.Links.Precedes = lb.Linkf("/effects?order=asc&cursor=%s", base.PT) - base.Links.Effects = lb.Link(self, "effects") - return base, nil + // TODO: Figure out what this means? Maybe @tamirms knows. + // if transactionHash != row.TransactionHash { + // dest.Signatures = dest.InnerTransaction.Signatures + // } + } else { + dest.FeeAccount = dest.Account + dest.FeeAccountMuxed = dest.AccountMuxed + dest.FeeAccountMuxedID = dest.AccountMuxedID + dest.MaxFee = int64(tx.Envelope.Fee()) + } + dest.FeeCharged = int64(tx.Result.Result.FeeCharged) + + lb := hal.LinkBuilder{Base: baseUrl} + dest.PT = strconv.FormatUint(uint64(tx.TOID()), 10) + dest.Links.Account = lb.Link("/accounts", dest.Account) + dest.Links.Ledger = lb.Link("/ledgers", fmt.Sprint(dest.Ledger)) + dest.Links.Operations = lb.PagedLink("/transactions", dest.ID, "operations") + dest.Links.Effects = lb.PagedLink("/transactions", dest.ID, "effects") + dest.Links.Self = lb.Link("/transactions", dest.ID) + dest.Links.Transaction = dest.Links.Self + dest.Links.Succeeds = lb.Linkf("/transactions?order=desc&cursor=%s", dest.PT) + dest.Links.Precedes = lb.Linkf("/transactions?order=asc&cursor=%s", dest.PT) + + // If we didn't need the structure, drop it. + if !tx.HasPreconditions() { + dest.Preconditions = nil + } + + return +} + +func formatSigners(s []xdr.SignerKey) []string { + if s == nil { + return nil + } + + signers := make([]string, len(s)) + for i, key := range s { + signers[i] = key.Address() + } + return signers +} + +func signatures(xdrSignatures []xdr.DecoratedSignature) []string { + signatures := make([]string, len(xdrSignatures)) + for i, sig := range xdrSignatures { + signatures[i] = base64.StdEncoding.EncodeToString(sig.Signature) + } + return signatures +} + +func memoType(transaction archive.LedgerTransaction) string { + switch transaction.Envelope.Memo().Type { + case xdr.MemoTypeMemoNone: + return "none" + case xdr.MemoTypeMemoText: + return "text" + case xdr.MemoTypeMemoId: + return "id" + case xdr.MemoTypeMemoHash: + return "hash" + case xdr.MemoTypeMemoReturn: + return "return" + default: + panic(fmt.Errorf("invalid memo type: %v", transaction.Envelope.Memo().Type)) + } +} + +func memo(transaction archive.LedgerTransaction) (value string, valid bool) { + valid = true + memo := transaction.Envelope.Memo() + + switch memo.Type { + case xdr.MemoTypeMemoNone: + value, valid = "", false + + case xdr.MemoTypeMemoText: + scrubbed := scrub(memo.MustText()) + notnull := strings.Join(strings.Split(scrubbed, "\x00"), "") + value = notnull + + case xdr.MemoTypeMemoId: + value = fmt.Sprintf("%d", memo.MustId()) + + case xdr.MemoTypeMemoHash: + hash := memo.MustHash() + value = base64.StdEncoding.EncodeToString(hash[:]) + + case xdr.MemoTypeMemoReturn: + hash := memo.MustRetHash() + value = base64.StdEncoding.EncodeToString(hash[:]) + + default: + panic(fmt.Errorf("invalid memo type: %v", memo.Type)) + } + + return +} + +func memoBytes(envelopeXDR string) (string, error) { + var parsedEnvelope xdr.TransactionEnvelope + if err := xdr.SafeUnmarshalBase64(envelopeXDR, &parsedEnvelope); err != nil { + return "", err + } + + memo := *parsedEnvelope.Memo().Text + return base64.StdEncoding.EncodeToString([]byte(memo)), nil +} + +// scrub ensures that a given string is valid utf-8, replacing any invalid byte +// sequences with the utf-8 replacement character. +func scrub(in string) string { + // First check validity using the stdlib, returning if the string is already + // valid + if utf8.ValidString(in) { + return in + } + + left := []byte(in) + var result bytes.Buffer + + for len(left) > 0 { + r, n := utf8.DecodeRune(left) + result.WriteRune(r) // never errors, only panics + left = left[n:] + } + + return result.String() +} + +func formatTime[T constraints.Integer](t T) string { + return strconv.FormatUint(uint64(t), 10) } diff --git a/exp/lighthorizon/adapters/transaction_test.go b/exp/lighthorizon/adapters/transaction_test.go new file mode 100644 index 0000000000..1eac3042f7 --- /dev/null +++ b/exp/lighthorizon/adapters/transaction_test.go @@ -0,0 +1,78 @@ +package adapters + +import ( + "encoding/json" + "net/url" + "os" + "path/filepath" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/stellar/go/exp/lighthorizon/archive" + "github.com/stellar/go/exp/lighthorizon/common" + "github.com/stellar/go/network" + protocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +// TestTransactionAdapter confirms that the adapter correctly serializes a +// transaction to JSON by actually pulling a transaction from the +// known-to-be-true horizon.stellar.org, turning it into an "ingested" +// transaction, and serializing it. +func TestTransactionAdapter(t *testing.T) { + f, err := os.Open(filepath.Join("./testdata", "transactions.json")) + require.NoErrorf(t, err, "are fixtures missing?") + + page := protocol.TransactionsPage{} + decoder := json.NewDecoder(f) + require.NoError(t, decoder.Decode(&page)) + require.Len(t, page.Embedded.Records, 1) + expectedTx := page.Embedded.Records[0] + + parsedUrl, err := url.Parse(page.Links.Self.Href) + require.NoError(t, err) + parsedToid, err := strconv.ParseInt(expectedTx.PagingToken(), 10, 64) + require.NoError(t, err) + expectedTxIndex := toid.Parse(parsedToid).TransactionOrder + + txEnv := xdr.TransactionEnvelope{} + txResult := xdr.TransactionResult{} + txMeta := xdr.TransactionMeta{} + txFeeMeta := xdr.LedgerEntryChanges{} + + require.NoError(t, xdr.SafeUnmarshalBase64(expectedTx.EnvelopeXdr, &txEnv)) + require.NoError(t, xdr.SafeUnmarshalBase64(expectedTx.ResultMetaXdr, &txMeta)) + require.NoError(t, xdr.SafeUnmarshalBase64(expectedTx.ResultXdr, &txResult)) + require.NoError(t, xdr.SafeUnmarshalBase64(expectedTx.FeeMetaXdr, &txFeeMeta)) + + closeTimestamp := expectedTx.LedgerCloseTime.UTC().Unix() + + tx := common.Transaction{ + LedgerTransaction: &archive.LedgerTransaction{ + Index: 0, + Envelope: txEnv, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{}, + Result: txResult, + }, + FeeChanges: txFeeMeta, + UnsafeMeta: txMeta, + }, + LedgerHeader: &xdr.LedgerHeader{ + LedgerSeq: xdr.Uint32(expectedTx.Ledger), + ScpValue: xdr.StellarValue{ + CloseTime: xdr.TimePoint(closeTimestamp), + }, + }, + TxIndex: expectedTxIndex - 1, // TOIDs have a 1-based index + NetworkPassphrase: network.PublicNetworkPassphrase, + } + + result, err := PopulateTransaction(parsedUrl, &tx, xdr.NewEncodingBuffer()) + require.NoError(t, err) + assert.Equal(t, expectedTx, result) +} diff --git a/exp/lighthorizon/build/index-batch/README.md b/exp/lighthorizon/build/index-batch/README.md new file mode 100644 index 0000000000..df4061d76d --- /dev/null +++ b/exp/lighthorizon/build/index-batch/README.md @@ -0,0 +1,7 @@ +# `stellar/horizon-indexer` + +This docker image contains the ledger/checkpoint indexing executables. It allows running multiple instances of `map`/`reduce` on a single machine or running it in [AWS Batch](https://aws.amazon.com/batch/). + +## Env variables + +See the [package documentation](../../index/cmd/batch/doc.go) for more details diff --git a/exp/lighthorizon/build/index-batch/start b/exp/lighthorizon/build/index-batch/start index 01540bc7fe..88fb5335fb 100644 --- a/exp/lighthorizon/build/index-batch/start +++ b/exp/lighthorizon/build/index-batch/start @@ -5,7 +5,6 @@ set -e export TRACY_NO_INVARIANT_CHECK=1 NETWORK_PASSPHRASE="${NETWORK_PASSPHRASE:=Public Global Stellar Network ; September 2015}" - if [ "$RUN_MODE" == "reduce" ]; then echo "Running Reduce, REDUCE JOBS: $REDUCE_JOB_COUNT MAP JOBS: $MAP_JOB_COUNT TARGET INDEX: $INDEX_TARGET" /reduce diff --git a/exp/lighthorizon/build/k8s/lighthorizon_batch_map_job.yml b/exp/lighthorizon/build/k8s/lighthorizon_batch_map_job.yml new file mode 100644 index 0000000000..a2671b66c1 --- /dev/null +++ b/exp/lighthorizon/build/k8s/lighthorizon_batch_map_job.yml @@ -0,0 +1,43 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: 'batch-map-job' +spec: + completions: 52 + parallelism: 10 + completionMode: Indexed + template: + spec: + restartPolicy: Never + containers: + - name: 'worker' + image: 'stellar/lighthorizon-index-batch' + imagePullPolicy: Always + envFrom: + - secretRef: + name: + env: + - name: RUN_MODE + value: "map" + - name: BATCH_SIZE + value: "10048" + - name: FIRST_CHECKPOINT + value: "41426080" + - name: WORKER_COUNT + value: "8" + - name: TXMETA_SOURCE + value: "" + - name: JOB_INDEX_ENV + value: "JOB_COMPLETION_INDEX" + - name: NETWORK_PASSPHRASE + value: "pubnet" + - name: INDEX_TARGET + value: "url of target index" + resources: + limits: + cpu: 4 + memory: 5Gi + requests: + cpu: 500m + memory: 500Mi + \ No newline at end of file diff --git a/exp/lighthorizon/build/k8s/lighthorizon_batch_reduce_job copy.yml b/exp/lighthorizon/build/k8s/lighthorizon_batch_reduce_job copy.yml new file mode 100644 index 0000000000..20b5f7c63b --- /dev/null +++ b/exp/lighthorizon/build/k8s/lighthorizon_batch_reduce_job copy.yml @@ -0,0 +1,42 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: 'batch-reduce-job' +spec: + completions: 52 + parallelism: 10 + completionMode: Indexed + template: + spec: + restartPolicy: Never + containers: + - name: 'worker' + image: 'stellar/lighthorizon-index-batch' + imagePullPolicy: Always + envFrom: + - secretRef: + name: + env: + - name: RUN_MODE + value: "reduce" + - name: MAP_JOB_COUNT + value: 52 + - name: REDUCE_JOB_COUNT + value: 52 + - name: WORKER_COUNT + value: 8 + - name: INDEX_SOURCE_ROOT + value: "" + - name: JOB_INDEX_ENV + value: JOB_COMPLETION_INDEX + - name: INDEX_TARGET + value: "" + resources: + limits: + cpu: 4 + memory: 5Gi + requests: + cpu: 500m + memory: 500Mi + + \ No newline at end of file diff --git a/exp/lighthorizon/common/transaction.go b/exp/lighthorizon/common/transaction.go index 41c957c113..4a8b2cfe09 100644 --- a/exp/lighthorizon/common/transaction.go +++ b/exp/lighthorizon/common/transaction.go @@ -4,26 +4,31 @@ import ( "encoding/hex" "errors" + "github.com/stellar/go/exp/lighthorizon/archive" "github.com/stellar/go/network" "github.com/stellar/go/toid" "github.com/stellar/go/xdr" ) type Transaction struct { - TransactionEnvelope *xdr.TransactionEnvelope - TransactionResult *xdr.TransactionResult - LedgerHeader *xdr.LedgerHeader - TxIndex int32 + *archive.LedgerTransaction + LedgerHeader *xdr.LedgerHeader + TxIndex int32 NetworkPassphrase string } -func (o *Transaction) TransactionHash() (string, error) { - if o.NetworkPassphrase == "" { +// type Transaction struct { +// TransactionEnvelope *xdr.TransactionEnvelope +// TransactionResult *xdr.TransactionResult +// } + +func (tx *Transaction) TransactionHash() (string, error) { + if tx.NetworkPassphrase == "" { return "", errors.New("network passphrase unspecified") } - hash, err := network.HashTransactionInEnvelope(*o.TransactionEnvelope, o.NetworkPassphrase) + hash, err := network.HashTransactionInEnvelope(tx.Envelope, tx.NetworkPassphrase) if err != nil { return "", err } @@ -32,13 +37,34 @@ func (o *Transaction) TransactionHash() (string, error) { } func (o *Transaction) SourceAccount() xdr.MuxedAccount { - return o.TransactionEnvelope.SourceAccount() + return o.Envelope.SourceAccount() } -func (o *Transaction) TOID() int64 { +func (tx *Transaction) TOID() int64 { return toid.New( - int32(o.LedgerHeader.LedgerSeq), - o.TxIndex+1, - 1, + int32(tx.LedgerHeader.LedgerSeq), + // TOID indexing is 1-based, so the 1st tx comes at position 1, + tx.TxIndex+1, + // but the TOID of a transaction comes BEFORE any operation + 0, ).ToInt64() } + +func (tx *Transaction) HasPreconditions() bool { + switch pc := tx.Envelope.Preconditions(); pc.Type { + case xdr.PreconditionTypePrecondNone: + return false + case xdr.PreconditionTypePrecondTime: + return pc.TimeBounds != nil + case xdr.PreconditionTypePrecondV2: + // TODO: 2x check these + return (pc.V2.TimeBounds != nil || + pc.V2.LedgerBounds != nil || + pc.V2.MinSeqNum != nil || + pc.V2.MinSeqAge > 0 || + pc.V2.MinSeqLedgerGap > 0 || + len(pc.V2.ExtraSigners) > 0) + } + + return false +} diff --git a/exp/lighthorizon/index/backend/file.go b/exp/lighthorizon/index/backend/file.go index e414730308..062b1efcdb 100644 --- a/exp/lighthorizon/index/backend/file.go +++ b/exp/lighthorizon/index/backend/file.go @@ -20,11 +20,19 @@ type FileBackend struct { parallel uint32 } +// NewFileBackend connects to indices stored at `dir`, creating the directory if one doesn't +// exist, and uses `parallel` to control how many workers to use when flushing to disk. func NewFileBackend(dir string, parallel uint32) (*FileBackend, error) { if parallel <= 0 { parallel = 1 } + err := os.MkdirAll(dir, fs.ModeDir|0755) + if err != nil { + log.Errorf("Unable to mkdir %s, %v", dir, err) + return nil, err + } + return &FileBackend{ dir: dir, parallel: parallel, diff --git a/exp/lighthorizon/index/cmd/batch/map/main.go b/exp/lighthorizon/index/cmd/batch/map/main.go index 5df88d6272..384e99ee80 100644 --- a/exp/lighthorizon/index/cmd/batch/map/main.go +++ b/exp/lighthorizon/index/cmd/batch/map/main.go @@ -24,7 +24,7 @@ type BatchConfig struct { const ( batchSizeEnv = "BATCH_SIZE" - jobIndexEnv = "AWS_BATCH_JOB_ARRAY_INDEX" + jobIndexEnvName = "JOB_INDEX_ENV" firstCheckpointEnv = "FIRST_CHECKPOINT" txmetaSourceUrlEnv = "TXMETA_SOURCE" indexTargetUrlEnv = "INDEX_TARGET" @@ -39,6 +39,10 @@ func NewBatchConfig() (*BatchConfig, error) { return nil, errors.New("required parameter: " + indexTargetUrlEnv) } + jobIndexEnv := os.Getenv(jobIndexEnvName) + if jobIndexEnv == "" { + return nil, errors.New("env variable can't be empty " + jobIndexEnvName) + } jobIndex, err := strconv.ParseUint(os.Getenv(jobIndexEnv), 10, 32) if err != nil { return nil, errors.Wrap(err, "invalid parameter "+jobIndexEnv) diff --git a/exp/lighthorizon/index/cmd/batch/reduce/main.go b/exp/lighthorizon/index/cmd/batch/reduce/main.go index a6e82861da..9d40361dde 100644 --- a/exp/lighthorizon/index/cmd/batch/reduce/main.go +++ b/exp/lighthorizon/index/cmd/batch/reduce/main.go @@ -37,11 +37,16 @@ func ReduceConfigFromEnvironment() (*ReduceConfig, error) { mapJobsEnv = "MAP_JOB_COUNT" reduceJobsEnv = "REDUCE_JOB_COUNT" workerCountEnv = "WORKER_COUNT" - jobIndexEnv = "AWS_BATCH_JOB_ARRAY_INDEX" + jobIndexEnvName = "JOB_INDEX_ENV" indexRootSourceEnv = "INDEX_SOURCE_ROOT" indexTargetEnv = "INDEX_TARGET" ) + jobIndexEnv := os.Getenv(jobIndexEnvName) + if jobIndexEnv == "" { + return nil, errors.New("env variable can't be empty " + jobIndexEnvName) + } + jobIndex, err := strconv.ParseUint(strings.TrimSpace(os.Getenv(jobIndexEnv)), 10, 32) if err != nil { return nil, errors.Wrap(err, "invalid parameter "+jobIndexEnv) diff --git a/exp/lighthorizon/index/cmd/map.sh b/exp/lighthorizon/index/cmd/map.sh index b85b7838f8..390370f2cb 100755 --- a/exp/lighthorizon/index/cmd/map.sh +++ b/exp/lighthorizon/index/cmd/map.sh @@ -68,7 +68,7 @@ for (( i=0; i < $BATCH_COUNT; i++ )) do echo -n "Creating map job $i... " - NETWORK_PASSPHRASE='testnet' MODULES='accounts_unbacked,transactions' \ + NETWORK_PASSPHRASE='testnet' JOB_INDEX_ENV='AWS_BATCH_JOB_ARRAY_INDEX' MODULES='accounts_unbacked,transactions' \ AWS_BATCH_JOB_ARRAY_INDEX=$i BATCH_SIZE=$BATCH_SIZE FIRST_CHECKPOINT=$FIRST \ TXMETA_SOURCE=file://$1 INDEX_TARGET=file://$2 WORKER_COUNT=1 \ ./map & diff --git a/exp/lighthorizon/index/cmd/reduce.sh b/exp/lighthorizon/index/cmd/reduce.sh index e89b91c474..1cfbca0ccc 100755 --- a/exp/lighthorizon/index/cmd/reduce.sh +++ b/exp/lighthorizon/index/cmd/reduce.sh @@ -47,7 +47,7 @@ for (( i=0; i < $REDUCE_JOB_COUNT; i++ )) do echo -n "Creating reduce job $i... " - AWS_BATCH_JOB_ARRAY_INDEX=$i MAP_JOB_COUNT=$MAP_JOB_COUNT \ + AWS_BATCH_JOB_ARRAY_INDEX=$i JOB_INDEX_ENV="AWS_BATCH_JOB_ARRAY_INDEX" MAP_JOB_COUNT=$MAP_JOB_COUNT \ REDUCE_JOB_COUNT=$REDUCE_JOB_COUNT WORKER_COUNT=4 \ INDEX_SOURCE_ROOT=file://$1 INDEX_TARGET=file://$2 \ timeout -k 30s 10s ./reduce & diff --git a/exp/lighthorizon/index/cmd/single_test.go b/exp/lighthorizon/index/cmd/single_test.go index 125058a387..58620d2ef9 100644 --- a/exp/lighthorizon/index/cmd/single_test.go +++ b/exp/lighthorizon/index/cmd/single_test.go @@ -23,7 +23,7 @@ import ( ) const ( - txmetaSource = "file://./fixtures/" + txmetaSource = "file://./testdata/" ) /** diff --git a/exp/lighthorizon/index/cmd/fixtures/latest b/exp/lighthorizon/index/cmd/testdata/latest similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/latest rename to exp/lighthorizon/index/cmd/testdata/latest diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410048 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410048 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410048 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410048 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410049 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410049 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410049 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410049 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410050 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410050 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410050 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410050 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410051 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410051 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410051 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410051 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410052 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410052 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410052 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410052 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410053 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410053 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410053 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410053 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410054 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410054 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410054 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410054 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410055 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410055 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410055 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410055 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410056 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410056 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410056 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410056 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410057 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410057 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410057 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410057 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410058 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410058 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410058 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410058 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410059 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410059 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410059 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410059 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410060 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410060 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410060 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410060 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410061 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410061 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410061 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410061 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410062 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410062 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410062 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410062 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410063 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410063 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410063 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410063 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410064 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410064 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410064 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410064 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410065 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410065 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410065 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410065 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410066 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410066 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410066 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410066 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410067 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410067 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410067 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410067 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410068 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410068 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410068 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410068 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410069 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410069 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410069 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410069 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410070 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410070 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410070 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410070 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410071 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410071 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410071 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410071 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410072 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410072 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410072 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410072 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410073 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410073 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410073 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410073 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410074 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410074 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410074 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410074 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410075 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410075 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410075 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410075 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410076 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410076 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410076 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410076 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410077 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410077 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410077 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410077 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410078 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410078 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410078 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410078 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410079 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410079 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410079 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410079 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410080 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410080 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410080 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410080 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410081 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410081 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410081 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410081 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410082 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410082 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410082 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410082 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410083 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410083 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410083 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410083 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410084 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410084 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410084 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410084 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410085 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410085 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410085 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410085 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410086 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410086 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410086 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410086 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410087 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410087 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410087 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410087 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410088 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410088 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410088 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410088 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410089 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410089 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410089 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410089 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410090 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410090 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410090 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410090 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410091 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410091 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410091 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410091 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410092 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410092 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410092 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410092 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410093 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410093 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410093 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410093 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410094 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410094 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410094 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410094 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410095 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410095 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410095 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410095 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410096 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410096 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410096 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410096 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410097 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410097 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410097 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410097 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410098 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410098 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410098 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410098 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410099 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410099 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410099 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410099 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410100 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410100 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410100 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410100 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410101 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410101 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410101 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410101 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410102 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410102 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410102 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410102 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410103 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410103 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410103 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410103 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410104 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410104 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410104 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410104 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410105 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410105 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410105 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410105 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410106 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410106 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410106 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410106 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410107 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410107 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410107 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410107 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410108 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410108 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410108 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410108 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410109 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410109 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410109 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410109 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410110 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410110 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410110 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410110 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410111 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410111 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410111 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410111 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410112 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410112 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410112 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410112 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410113 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410113 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410113 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410113 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410114 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410114 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410114 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410114 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410115 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410115 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410115 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410115 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410116 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410116 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410116 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410116 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410117 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410117 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410117 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410117 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410118 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410118 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410118 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410118 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410119 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410119 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410119 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410119 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410120 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410120 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410120 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410120 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410121 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410121 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410121 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410121 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410122 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410122 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410122 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410122 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410123 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410123 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410123 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410123 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410124 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410124 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410124 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410124 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410125 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410125 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410125 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410125 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410126 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410126 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410126 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410126 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410127 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410127 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410127 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410127 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410128 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410128 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410128 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410128 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410129 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410129 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410129 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410129 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410130 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410130 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410130 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410130 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410131 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410131 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410131 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410131 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410132 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410132 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410132 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410132 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410133 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410133 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410133 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410133 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410134 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410134 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410134 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410134 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410135 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410135 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410135 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410135 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410136 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410136 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410136 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410136 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410137 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410137 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410137 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410137 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410138 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410138 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410138 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410138 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410139 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410139 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410139 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410139 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410140 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410140 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410140 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410140 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410141 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410141 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410141 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410141 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410142 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410142 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410142 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410142 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410143 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410143 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410143 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410143 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410144 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410144 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410144 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410144 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410145 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410145 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410145 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410145 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410146 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410146 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410146 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410146 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410147 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410147 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410147 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410147 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410148 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410148 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410148 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410148 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410149 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410149 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410149 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410149 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410150 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410150 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410150 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410150 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410151 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410151 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410151 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410151 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410152 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410152 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410152 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410152 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410153 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410153 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410153 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410153 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410154 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410154 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410154 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410154 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410155 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410155 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410155 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410155 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410156 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410156 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410156 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410156 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410157 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410157 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410157 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410157 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410158 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410158 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410158 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410158 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410159 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410159 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410159 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410159 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410160 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410160 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410160 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410160 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410161 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410161 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410161 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410161 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410162 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410162 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410162 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410162 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410163 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410163 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410163 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410163 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410164 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410164 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410164 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410164 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410165 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410165 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410165 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410165 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410166 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410166 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410166 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410166 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410167 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410167 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410167 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410167 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410168 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410168 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410168 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410168 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410169 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410169 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410169 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410169 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410170 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410170 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410170 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410170 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410171 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410171 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410171 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410171 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410172 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410172 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410172 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410172 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410173 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410173 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410173 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410173 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410174 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410174 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410174 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410174 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410175 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410175 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410175 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410175 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410176 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410176 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410176 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410176 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410177 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410177 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410177 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410177 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410178 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410178 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410178 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410178 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410179 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410179 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410179 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410179 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410180 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410180 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410180 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410180 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410181 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410181 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410181 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410181 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410182 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410182 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410182 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410182 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410183 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410183 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410183 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410183 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410184 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410184 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410184 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410184 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410185 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410185 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410185 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410185 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410186 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410186 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410186 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410186 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410187 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410187 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410187 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410187 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410188 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410188 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410188 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410188 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410189 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410189 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410189 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410189 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410190 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410190 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410190 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410190 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410191 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410191 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410191 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410191 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410192 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410192 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410192 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410192 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410193 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410193 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410193 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410193 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410194 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410194 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410194 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410194 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410195 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410195 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410195 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410195 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410196 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410196 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410196 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410196 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410197 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410197 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410197 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410197 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410198 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410198 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410198 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410198 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410199 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410199 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410199 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410199 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410200 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410200 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410200 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410200 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410201 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410201 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410201 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410201 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410202 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410202 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410202 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410202 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410203 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410203 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410203 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410203 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410204 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410204 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410204 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410204 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410205 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410205 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410205 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410205 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410206 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410206 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410206 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410206 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410207 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410207 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410207 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410207 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410208 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410208 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410208 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410208 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410209 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410209 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410209 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410209 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410210 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410210 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410210 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410210 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410211 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410211 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410211 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410211 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410212 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410212 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410212 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410212 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410213 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410213 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410213 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410213 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410214 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410214 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410214 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410214 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410215 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410215 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410215 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410215 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410216 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410216 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410216 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410216 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410217 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410217 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410217 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410217 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410218 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410218 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410218 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410218 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410219 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410219 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410219 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410219 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410220 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410220 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410220 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410220 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410221 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410221 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410221 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410221 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410222 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410222 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410222 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410222 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410223 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410223 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410223 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410223 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410224 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410224 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410224 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410224 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410225 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410225 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410225 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410225 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410226 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410226 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410226 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410226 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410227 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410227 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410227 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410227 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410228 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410228 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410228 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410228 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410229 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410229 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410229 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410229 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410230 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410230 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410230 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410230 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410231 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410231 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410231 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410231 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410232 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410232 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410232 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410232 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410233 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410233 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410233 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410233 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410234 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410234 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410234 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410234 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410235 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410235 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410235 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410235 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410236 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410236 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410236 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410236 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410237 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410237 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410237 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410237 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410238 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410238 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410238 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410238 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410239 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410239 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410239 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410239 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410240 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410240 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410240 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410240 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410241 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410241 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410241 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410241 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410242 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410242 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410242 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410242 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410243 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410243 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410243 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410243 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410244 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410244 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410244 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410244 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410245 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410245 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410245 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410245 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410246 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410246 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410246 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410246 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410247 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410247 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410247 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410247 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410248 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410248 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410248 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410248 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410249 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410249 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410249 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410249 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410250 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410250 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410250 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410250 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410251 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410251 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410251 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410251 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410252 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410252 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410252 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410252 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410253 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410253 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410253 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410253 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410254 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410254 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410254 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410254 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410255 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410255 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410255 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410255 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410256 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410256 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410256 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410256 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410257 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410257 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410257 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410257 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410258 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410258 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410258 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410258 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410259 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410259 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410259 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410259 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410260 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410260 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410260 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410260 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410261 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410261 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410261 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410261 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410262 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410262 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410262 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410262 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410263 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410263 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410263 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410263 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410264 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410264 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410264 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410264 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410265 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410265 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410265 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410265 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410266 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410266 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410266 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410266 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410267 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410267 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410267 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410267 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410268 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410268 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410268 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410268 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410269 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410269 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410269 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410269 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410270 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410270 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410270 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410270 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410271 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410271 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410271 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410271 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410272 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410272 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410272 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410272 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410273 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410273 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410273 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410273 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410274 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410274 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410274 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410274 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410275 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410275 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410275 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410275 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410276 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410276 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410276 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410276 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410277 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410277 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410277 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410277 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410278 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410278 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410278 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410278 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410279 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410279 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410279 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410279 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410280 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410280 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410280 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410280 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410281 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410281 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410281 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410281 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410282 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410282 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410282 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410282 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410283 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410283 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410283 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410283 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410284 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410284 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410284 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410284 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410285 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410285 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410285 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410285 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410286 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410286 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410286 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410286 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410287 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410287 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410287 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410287 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410288 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410288 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410288 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410288 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410289 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410289 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410289 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410289 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410290 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410290 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410290 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410290 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410291 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410291 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410291 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410291 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410292 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410292 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410292 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410292 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410293 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410293 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410293 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410293 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410294 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410294 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410294 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410294 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410295 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410295 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410295 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410295 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410296 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410296 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410296 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410296 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410297 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410297 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410297 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410297 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410298 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410298 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410298 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410298 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410299 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410299 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410299 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410299 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410300 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410300 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410300 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410300 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410301 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410301 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410301 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410301 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410302 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410302 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410302 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410302 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410303 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410303 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410303 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410303 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410304 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410304 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410304 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410304 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410305 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410305 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410305 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410305 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410306 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410306 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410306 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410306 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410307 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410307 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410307 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410307 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410308 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410308 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410308 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410308 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410309 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410309 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410309 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410309 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410310 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410310 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410310 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410310 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410311 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410311 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410311 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410311 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410312 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410312 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410312 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410312 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410313 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410313 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410313 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410313 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410314 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410314 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410314 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410314 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410315 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410315 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410315 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410315 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410316 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410316 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410316 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410316 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410317 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410317 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410317 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410317 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410318 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410318 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410318 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410318 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410319 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410319 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410319 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410319 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410320 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410320 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410320 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410320 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410321 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410321 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410321 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410321 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410322 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410322 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410322 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410322 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410323 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410323 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410323 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410323 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410324 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410324 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410324 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410324 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410325 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410325 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410325 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410325 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410326 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410326 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410326 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410326 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410327 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410327 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410327 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410327 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410328 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410328 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410328 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410328 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410329 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410329 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410329 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410329 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410330 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410330 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410330 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410330 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410331 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410331 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410331 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410331 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410332 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410332 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410332 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410332 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410333 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410333 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410333 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410333 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410334 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410334 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410334 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410334 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410335 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410335 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410335 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410335 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410336 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410336 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410336 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410336 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410337 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410337 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410337 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410337 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410338 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410338 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410338 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410338 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410339 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410339 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410339 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410339 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410340 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410340 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410340 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410340 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410341 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410341 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410341 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410341 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410342 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410342 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410342 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410342 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410343 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410343 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410343 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410343 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410344 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410344 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410344 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410344 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410345 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410345 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410345 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410345 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410346 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410346 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410346 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410346 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410347 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410347 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410347 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410347 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410348 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410348 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410348 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410348 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410349 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410349 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410349 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410349 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410350 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410350 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410350 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410350 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410351 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410351 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410351 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410351 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410352 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410352 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410352 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410352 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410353 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410353 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410353 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410353 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410354 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410354 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410354 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410354 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410355 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410355 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410355 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410355 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410356 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410356 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410356 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410356 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410357 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410357 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410357 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410357 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410358 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410358 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410358 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410358 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410359 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410359 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410359 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410359 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410360 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410360 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410360 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410360 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410361 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410361 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410361 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410361 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410362 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410362 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410362 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410362 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410363 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410363 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410363 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410363 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410364 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410364 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410364 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410364 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410365 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410365 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410365 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410365 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410366 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410366 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410366 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410366 diff --git a/exp/lighthorizon/index/cmd/fixtures/ledgers/1410367 b/exp/lighthorizon/index/cmd/testdata/ledgers/1410367 similarity index 100% rename from exp/lighthorizon/index/cmd/fixtures/ledgers/1410367 rename to exp/lighthorizon/index/cmd/testdata/ledgers/1410367 diff --git a/exp/lighthorizon/index/cmd/fixtures/regenerate.sh b/exp/lighthorizon/index/cmd/testdata/regenerate.sh similarity index 63% rename from exp/lighthorizon/index/cmd/fixtures/regenerate.sh rename to exp/lighthorizon/index/cmd/testdata/regenerate.sh index 197c30e3f0..4cc0d9c50f 100644 --- a/exp/lighthorizon/index/cmd/fixtures/regenerate.sh +++ b/exp/lighthorizon/index/cmd/testdata/regenerate.sh @@ -1,3 +1,3 @@ #!/bin/bash -docker run -e WRITE_LATEST_PATH=true -e START=1410048 -e END=1410367 -e ARCHIVE_TARGET=file:///fixtures/ -v $PWD:/fixtures/ stellar/horizon-ledgerexporter:latest +docker run -e WRITE_LATEST_PATH=true -e START=1410048 -e END=1410367 -e ARCHIVE_TARGET=file:///testdata/ -v $PWD:/tetsdata/ stellar/horizon-ledgerexporter:latest diff --git a/exp/lighthorizon/main.go b/exp/lighthorizon/main.go index bc35c87649..16925f91cf 100644 --- a/exp/lighthorizon/main.go +++ b/exp/lighthorizon/main.go @@ -37,7 +37,6 @@ if left empty, uses a temporary directory`) log.Warnf("Failed to parse -log-level '%s', defaulting to 'info'.", *logLevelParam) logLevel = log.InfoLevel } - L.SetLevel(logLevel) L.Info("Starting lighthorizon!") diff --git a/exp/lighthorizon/services/transactions.go b/exp/lighthorizon/services/transactions.go index 8c015af308..42d3964614 100644 --- a/exp/lighthorizon/services/transactions.go +++ b/exp/lighthorizon/services/transactions.go @@ -32,11 +32,10 @@ func (tr *TransactionRepository) GetTransactionsByAccount(ctx context.Context, txsCallback := func(tx ingester.LedgerTransaction, ledgerHeader *xdr.LedgerHeader) (bool, error) { txs = append(txs, common.Transaction{ - TransactionEnvelope: &tx.Envelope, - TransactionResult: &tx.Result.Result, - LedgerHeader: ledgerHeader, - TxIndex: int32(tx.Index), - NetworkPassphrase: tr.Config.Passphrase, + LedgerTransaction: &tx, + LedgerHeader: ledgerHeader, + TxIndex: int32(tx.Index), + NetworkPassphrase: tr.Config.Passphrase, }) return uint64(len(txs)) == limit, nil diff --git a/exp/lighthorizon/tools/cache.go b/exp/lighthorizon/tools/cache.go index d32d1aa35a..29f24f408c 100644 --- a/exp/lighthorizon/tools/cache.go +++ b/exp/lighthorizon/tools/cache.go @@ -11,6 +11,7 @@ import ( "time" "github.com/spf13/cobra" + "github.com/stellar/go/metaarchive" "github.com/stellar/go/support/log" "github.com/stellar/go/support/storage" @@ -20,9 +21,7 @@ const ( defaultCacheCount = (60 * 60 * 24) / 5 // ~24hrs worth of ledgers ) -func main() { - log.SetLevel(log.InfoLevel) - +func addCacheCommands(parent *cobra.Command) *cobra.Command { cmd := &cobra.Command{ Use: "cache", Long: "Manages the on-disk cache of ledgers.", @@ -31,11 +30,11 @@ cache build --start 1234 --count 1000 s3://txmeta /tmp/example cache purge /tmp/example 1234 1300 cache show /tmp/example`, RunE: func(cmd *cobra.Command, args []string) error { - // require a subcommand for now - eventually this will live under - // the lighthorizon command + // require a subcommand - this is just a "category" return cmd.Help() }, } + purge := &cobra.Command{ Use: "purge [flags] path ", Long: "Purges individual ledgers (or ranges) from the cache, or the entire cache.", @@ -119,7 +118,12 @@ purge /tmp/example 1000 1005 # purge a ledger range`, build.Flags().Uint("count", defaultCacheCount, "number of ledgers to cache") cmd.AddCommand(build, purge, show) - cmd.Execute() + if parent == nil { + return cmd + } + + parent.AddCommand(cmd) + return parent } func BuildCache(ledgerSource, cacheDir string, start uint32, count uint, repair bool) error { diff --git a/exp/lighthorizon/tools/explorer.go b/exp/lighthorizon/tools/explorer.go new file mode 100644 index 0000000000..1978236a20 --- /dev/null +++ b/exp/lighthorizon/tools/explorer.go @@ -0,0 +1,259 @@ +package main + +import ( + "context" + "io" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/spf13/cobra" + + "github.com/stellar/go/exp/lighthorizon/index" + "github.com/stellar/go/historyarchive" + "github.com/stellar/go/strkey" + "github.com/stellar/go/support/collections/maps" + "github.com/stellar/go/support/collections/set" + "github.com/stellar/go/support/log" + "github.com/stellar/go/support/ordered" +) + +var ( + checkpointMgr = historyarchive.NewCheckpointManager(0) +) + +func addIndexCommands(parent *cobra.Command) *cobra.Command { + cmd := &cobra.Command{ + Use: "index", + Long: "Lets you view details about an index source.", + Example: ` +index view file:///tmp/indices +index view file:///tmp/indices GAGJZWQ5QT34VK3U6W6YKRYFIK6YSAXQC6BHIIYLG6X3CE5QW2KAYNJR +index stats file:///tmp/indices`, + RunE: func(cmd *cobra.Command, args []string) error { + // require a subcommand - this is just a "category" + return cmd.Help() + }, + } + + stats := &cobra.Command{ + Use: "stats ", + Long: "Summarize the statistics (like the # of active checkpoints " + + "or accounts). Note that this is a very read-heavy operation and " + + "will incur download bandwidth costs if reading from remote, " + + "billable sources.", + Example: `stats s3://indices`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return cmd.Usage() + } + + path := args[0] + start := time.Now() + log.Infof("Analyzing indices at %s", path) + + allCheckpoints := set.Set[uint32]{} + allIndexNames := set.Set[string]{} + accounts := showAccounts(path, 0) + log.Infof("Analyzing indices for %d accounts.", len(accounts)) + + // We want to summarize as much as possible on a Ctrl+C event, so + // this handles that by setting up a context that gets cancelled on + // SIGINT. A second Ctrl+C will kill the process as usual. + // + // https://millhouse.dev/posts/graceful-shutdowns-in-golang-with-signal-notify-context + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGINT) + defer stop() + go func() { + <-ctx.Done() + stop() + log.WithField("error", ctx.Err()). + Warn("Received interrupt, shutting down gracefully & summarizing findings...") + log.Warn("Press Ctrl+C again to abort.") + }() + + mostActiveAccountChk := 0 + mostActiveAccount := "" + for _, account := range accounts { + if ctx.Err() != nil { + break + } + + activity := getIndex(path, account, "", 0) + allCheckpoints.AddSlice(maps.Keys(activity)) + for _, names := range activity { + allIndexNames.AddSlice(names) + } + + if len(activity) > mostActiveAccountChk { + mostActiveAccount = account + mostActiveAccountChk = len(activity) + } + } + + ledgerCount := len(allCheckpoints) * int(checkpointMgr.GetCheckpointFrequency()) + + log.Info("Done analyzing indices, summarizing...") + log.Infof("") + log.Infof("=== Final Summary ===") + log.Infof("Analysis took %s.", time.Since(start)) + log.Infof("Path: %s", path) + log.Infof("Accounts: %d", len(accounts)) + log.Infof("Smallest checkpoint: %d", ordered.MinSlice(allCheckpoints.Slice())) + log.Infof("Largest checkpoint: %d", ordered.MaxSlice(allCheckpoints.Slice())) + log.Infof("Checkpoint count: %d (%d possible ledgers, ~%0.2f days)", + len(allCheckpoints), ledgerCount, + float64(ledgerCount)/(float64(60*60*24)/6.0) /* approx. ledgers per day */) + log.Infof("Index names: %s", strings.Join(allIndexNames.Slice(), ", ")) + log.Infof("Most active account: %s (%d checkpoints)", + mostActiveAccount, mostActiveAccountChk) + + return nil + }, + } + + view := &cobra.Command{ + Use: "view [accounts?]", + Long: "View the accounts in an index source or view the " + + "checkpoints specific account(s) are active in.", + Example: `view s3://indices +view s3:///indices GAXLQGKIUAIIUHAX4GJO3J7HFGLBCNF6ZCZSTLJE7EKO5IUHGLQLMXZO +view file:///tmp/indices --limit=0 GAXLQGKIUAIIUHAX4GJO3J7HFGLBCNF6ZCZSTLJE7EKO5IUHGLQLMXZO +view gcs://indices --limit=10 GAXLQGKIUAIIUHAX4GJO3J7HFGLBCNF6ZCZSTLJE7EKO5IUHGLQLMXZO,GBUUWQDVEEXBJCUF5UL24YGXKJIP5EMM7KFWIAR33KQRJR34GN6HEDPV,GBYETUYNBK2ZO5MSYBJKSLDEA2ZHIXLCFL3MMWU6RHFVAUBKEWQORYKS`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) > 2 { + return cmd.Usage() + } + + path := args[0] + log.Infof("Analyzing indices at %s", path) + + accounts := []string{} + if len(args) == 2 { + accounts = strings.Split(args[1], ",") + } + + limit, err := cmd.Flags().GetUint("limit") + if err != nil { + return cmd.Usage() + } + + if len(accounts) > 0 { + indexName, err := cmd.Flags().GetString("index-name") + if err != nil { + return cmd.Usage() + } + + for _, account := range accounts { + if !strkey.IsValidEd25519PublicKey(account) && + !strkey.IsValidMuxedAccountEd25519PublicKey(account) { + log.Errorf("Invalid account ID: '%s'", account) + continue + } + + getIndex(path, account, indexName, limit) + } + } else { + showAccounts(path, limit) + } + + return nil + }, + } + + view.Flags().Uint("limit", 10, "a maximum number of accounts or checkpoints to show") + view.Flags().String("index-name", "", "filter for a particular index") + cmd.AddCommand(stats, view) + + if parent == nil { + return cmd + } + parent.AddCommand(cmd) + return parent +} + +func getIndex(path, account, indexName string, limit uint) map[uint32][]string { + freq := checkpointMgr.GetCheckpointFrequency() + + store, err := index.Connect(path) + if err != nil { + log.Fatal(err) + } + + indices, err := store.Read(account) + if err != nil { + log.Fatal(err) + } + + // It's better to summarize activity and then group it by index rather than + // just show activity in each index, because there's likely a ton of overlap + // across indices. + activity := map[uint32][]string{} + indexNames := []string{} + + for name, idx := range indices { + log.Infof("Index found: '%s'", name) + if indexName != "" && name != indexName { + continue + } + + indexNames = append(indexNames, name) + + checkpoint, err := idx.NextActiveBit(0) + for err != io.EOF { + activity[checkpoint] = append(activity[checkpoint], name) + checkpoint, err = idx.NextActiveBit(checkpoint + 1) + + if limit > 0 && limit <= uint(len(activity)) { + break + } + } + } + + log.WithField("account", account).WithField("limit", limit). + Infof("Activity for account:") + + for checkpoint, names := range activity { + first := (checkpoint - 1) * freq + last := first + freq + + nameStr := strings.Join(names, ", ") + log.WithField("indices", nameStr). + Infof(" - checkpoint %d, ledgers [%d, %d)", checkpoint, first, last) + } + + log.Infof("Summary: %d active checkpoints, %d possible active ledgers", + len(activity), len(activity)*int(freq)) + log.Infof("Checkpoint range: [%d, %d]", + ordered.MinSlice(maps.Keys(activity)), + ordered.MaxSlice(maps.Keys(activity))) + log.Infof("All discovered indices: %s", strings.Join(indexNames, ", ")) + + return activity +} + +func showAccounts(path string, limit uint) []string { + store, err := index.Connect(path) + if err != nil { + log.Fatalf("Failed to connect to index store at %s: %v", path, err) + return nil + } + + accounts, err := store.ReadAccounts() + if err != nil { + log.Fatalf("Failed read accounts from index store at %s: %v", path, err) + return nil + } + + if limit == 0 { + limit = uint(len(accounts)) + } + + for i := uint(0); i < limit; i++ { + log.Info(accounts[i]) + } + + return accounts +} diff --git a/exp/lighthorizon/tools/main.go b/exp/lighthorizon/tools/main.go new file mode 100644 index 0000000000..d57021becb --- /dev/null +++ b/exp/lighthorizon/tools/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "github.com/spf13/cobra" + + "github.com/stellar/go/support/log" +) + +func main() { + log.SetLevel(log.InfoLevel) + + cmd := &cobra.Command{ + Use: "tools", + Long: "Please specify a subcommand to use this toolset.", + Example: "", + RunE: func(cmd *cobra.Command, args []string) error { + // require a subcommand - this is just a "category" + return cmd.Help() + }, + } + + cmd = addCacheCommands(cmd) + cmd = addIndexCommands(cmd) + cmd.Execute() +} diff --git a/support/collections/set/set.go b/support/collections/set/set.go index f7a2d3adea..292b71c4f8 100644 --- a/support/collections/set/set.go +++ b/support/collections/set/set.go @@ -24,3 +24,11 @@ func (set Set[T]) Contains(item T) bool { _, ok := set[item] return ok } + +func (set Set[T]) Slice() []T { + slice := make([]T, 0, len(set)) + for key := range set { + slice = append(slice, key) + } + return slice +} diff --git a/support/ordered/math.go b/support/ordered/math.go index a07f7064c4..1bf2a40031 100644 --- a/support/ordered/math.go +++ b/support/ordered/math.go @@ -19,3 +19,29 @@ func Max[T constraints.Ordered](a, b T) T { } return b } + +// MinSlice returns the smallest element in a slice-like container. +func MinSlice[T constraints.Ordered](slice []T) T { + var smallest T + + for i := 0; i < len(slice); i++ { + if i == 0 || slice[i] < smallest { + smallest = slice[i] + } + } + + return smallest +} + +// MaxSlice returns the largest element in a slice-like container. +func MaxSlice[T constraints.Ordered](slice []T) T { + var largest T + + for i := 0; i < len(slice); i++ { + if i == 0 || slice[i] > largest { + largest = slice[i] + } + } + + return largest +}