All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.savl.ripple.client.subscriptions.ledger.PendingLedgers Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
package com.savl.ripple.client.subscriptions.ledger;

import com.savl.ripple.client.Client;
import com.savl.ripple.client.enums.Command;
import com.savl.ripple.client.requests.Request;
import com.savl.ripple.client.responses.Response;
import com.savl.ripple.core.types.known.tx.result.TransactionResult;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.Set;
import java.util.TreeMap;

import static com.savl.ripple.client.pubsub.Publisher.Callback;

public class PendingLedgers {
    Client client;
    TreeMap ledgers = new TreeMap();
    ClearedLedgersSet clearedLedgers = new ClearedLedgersSet();

    public PendingLedgers(Client clientInstance) {
        client = clientInstance;
    }

    public PendingLedger getOrAddLedger(long ledger_index) {
        PendingLedger ledger = ledgers.get(ledger_index);

        if (ledger == null) {
            ledger = constructAndAddLedger(ledger_index);
        }
        return ledger;
    }

    private PendingLedger constructAndAddLedger(long ledger_index) {
        if (clearedLedgers.contains(ledger_index)) throw new AssertionError();

        PendingLedger ledger = new PendingLedger(ledger_index, client);
        ledgers.put(ledger_index, ledger);
        return ledger;
    }

    public void clearLedger(long ledger_index, String from) {
        // We are using this to test our logic wrt, to when it's safe to
        // to clear the `clearedLedgers` set.
        clearedLedgers.clear(ledger_index);
        PendingLedger remove = ledgers.remove(ledger_index);
        if (remove == null) throw new AssertionError();
        remove.setStatus(PendingLedger.Status.cleared);

        if (ledgers.size() == 1) {
            clearedLedgers.clearIfNoGaps();
        }
    }

    public void notifyTransactionResult(TransactionResult tr) {
        long key = tr.ledgerIndex.longValue();
        if (clearedLedgers.contains(key)) {
            System.out.println("warning");
            return;
        }

        PendingLedger ledger = getOrAddLedger(key);
        ledger.notifyTransaction(tr);
    }

    private void requestLedger(final long ledger_index, final boolean onlyHeader, final Callback cb) {
        Request request = client.newRequest(Command.ledger);
        request.json("ledger_index", ledger_index);
        if (!onlyHeader) {
            request.json("transactions", true);
            request.json("expand", true);
        }

        request.once(Request.OnResponse.class, new Request.OnResponse() {
            @Override
            public void called(Response response) {
                if (response.succeeded) {
                    cb.called(response);
                } else {
                    System.out.println("PendingLedgers.called");
                    System.out.println(response.message);

                    client.schedule(1000, new Runnable() {
                        @Override
                        public void run() {
                            requestLedger(ledger_index, onlyHeader, cb);
                        }
                    });
                }
            }
        });
        request.request();
    }

    void checkHeader(final PendingLedger ledger) {
        final long ledger_index = ledger.ledger_index;
        ledger.setStatus(PendingLedger.Status.checkingHeader);

        requestLedger(ledger_index, true, new Callback() {
            @Override
            public void called(Response response) {
                JSONObject ledgerJSON = response.result.getJSONObject("ledger");
                final String transaction_hash = ledgerJSON.getString("transaction_hash");
                boolean correctHash = ledger.transactionHashEquals(transaction_hash);
                if (correctHash) {
                    clearLedger(ledger_index, "checkHeader");
                } else {
                    LedgerSubscriber.log("Missing transactions, need to fillInLedger: " + ledger);
                    fillInLedger(ledger);
                }
            }
        });
    }

    void fillInLedger(final PendingLedger ledger) {
        final long ledger_index = ledger.ledger_index;
        ledger.setStatus(PendingLedger.Status.fillingIn);

        requestLedger(ledger_index, false, new Callback() {
            @Override
            public void called(Response response) {
                JSONObject ledgerJSON = response.result.getJSONObject("ledger");
                JSONArray transactions = ledgerJSON.getJSONArray("transactions");

                for (int i = 0; i < transactions.length(); i++) {
                    JSONObject json = transactions.getJSONObject(i);
                    // This is kind of nasty
                    json.put("ledger_index", ledger_index);
                    json.put("validated",    true);
                    TransactionResult tr = TransactionResult.fromJSON(json);
                    ledger.notifyTransaction(tr);
                }

                final String transaction_hash = ledgerJSON.getString("transaction_hash");
                boolean correctHash = ledger.transactionHashEquals(transaction_hash);
                if (!correctHash) throw new IllegalStateException("We don't handle invalid transactions yet");
                clearLedger(ledger_index, "fillInLedger");
            }
        });
    }

    public boolean alreadyPending(long j) {
        return ledgers.containsKey(j);
    }

    /**
     * We can't just look for gaps in the ledgers keys as they are popped
     * off randomly as the ledgers clear.
     */
    void trackMissingLedgersInClearedLedgerHistory() {
        for (Long j : clearedLedgers.gaps()) {
            if (!alreadyPending(j)) {
                constructAndAddLedger(j);
            }
        }
    }

    Set pendingLedgerIndexes() {
        return ledgers.keySet();
    }

    public void logPendingLedgers() {
        for (PendingLedger pendingLedger : ledgers.values()) {
            System.out.println(pendingLedger);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy