Skip to content

Commit

Permalink
Remove DaoExplorerService and move method to DaoStateService
Browse files Browse the repository at this point in the history
Add BlockDataToJsonConverter for blockdata to json conversion

Signed-off-by: HenrikJannsen <[email protected]>
  • Loading branch information
HenrikJannsen committed Jul 21, 2024
1 parent bd9136f commit 20e7a38
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 316 deletions.
53 changes: 53 additions & 0 deletions core/src/main/java/bisq/core/dao/state/DaoStateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
Expand All @@ -75,6 +77,7 @@ public class DaoStateService implements DaoSetupService {
@Getter
private boolean parseBlockChainComplete;
private boolean allowDaoStateChange;
private final Map<String, Set<String>> cachedTxIdSetByAddress = new HashMap<>();


///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -299,6 +302,10 @@ public void onParseBlockComplete(Block block) {
// generate a hash of the state.
allowDaoStateChange = false;
daoStateListeners.forEach(l -> l.onDaoStateChanged(block));

if (!block.getTxs().isEmpty()) {
cachedTxIdSetByAddress.clear();
}
}

// Called after parsing of all pending blocks is completed
Expand Down Expand Up @@ -1031,6 +1038,52 @@ public Optional<SpentInfo> getSpentInfo(TxOutput txOutput) {
}


///////////////////////////////////////////////////////////////////////////////////////////
// Addresses
///////////////////////////////////////////////////////////////////////////////////////////

public Map<String, Set<String>> getTxIdSetByAddress() {
// We clear it at each new (non-empty) block, so it gets recreated
if (!cachedTxIdSetByAddress.isEmpty()) {
return cachedTxIdSetByAddress;
}

Map<TxOutputKey, String> txIdByConnectedTxOutputKey = new HashMap<>();
// Add tx ids and addresses from tx outputs
getUnorderedTxStream()
.forEach(tx -> {
tx.getTxOutputs().stream()
.filter(this::isBsqTxOutputType)
.filter(txOutput -> txOutput.getAddress() != null)
.forEach(txOutput -> {
String address = txOutput.getAddress();
Set<String> txIdSet = cachedTxIdSetByAddress.getOrDefault(address, new HashSet<>());
String txId = tx.getId();
txIdSet.add(txId);
cachedTxIdSetByAddress.put(address, txIdSet);
tx.getTxInputs().forEach(txInput -> {
txIdByConnectedTxOutputKey.put(txInput.getConnectedTxOutputKey(), txId);
});
});
});

// Add tx ids and addresses from connected outputs (inputs)
getUnorderedTxOutputStream()
.filter(this::isBsqTxOutputType)
.filter(txOutput -> txOutput.getAddress() != null)
.forEach(txOutput -> {
String txId = txIdByConnectedTxOutputKey.get(txOutput.getKey());
if (txId != null) {
String address = txOutput.getAddress();
Set<String> txIdSet = cachedTxIdSetByAddress.getOrDefault(address, new HashSet<>());
txIdSet.add(txId);
cachedTxIdSetByAddress.put(address, txIdSet);
}
});

return cachedTxIdSetByAddress;
}

///////////////////////////////////////////////////////////////////////////////////////////
// Vote result data
///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
128 changes: 128 additions & 0 deletions restapi/src/main/java/bisq/restapi/BlockDataToJsonConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package bisq.restapi;

import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.dao.state.model.blockchain.PubKeyScript;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.dao.state.model.blockchain.TxOutput;
import bisq.core.dao.state.model.blockchain.TxType;

import com.google.common.io.BaseEncoding;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;



import bisq.restapi.dto.JsonBlock;
import bisq.restapi.dto.JsonScriptPubKey;
import bisq.restapi.dto.JsonSpentInfo;
import bisq.restapi.dto.JsonTx;
import bisq.restapi.dto.JsonTxInput;
import bisq.restapi.dto.JsonTxOutput;
import bisq.restapi.dto.JsonTxOutputType;
import bisq.restapi.dto.JsonTxType;

@Slf4j
public class BlockDataToJsonConverter {
public static JsonBlock getJsonBlock(DaoStateService daoStateService, Block block) {
List<JsonTx> jsonTxs = block.getTxs().stream()
.map(tx -> getJsonTx(daoStateService, tx))
.collect(Collectors.toList());
return new JsonBlock(block.getHeight(),
block.getTime(),
block.getHash(),
block.getPreviousBlockHash(),
jsonTxs);
}

public static JsonTx getJsonTx(DaoStateService daoStateService, Tx tx) {
JsonTxType jsonTxType = getJsonTxType(tx);
String jsonTxTypeDisplayString = getJsonTxTypeDisplayString(jsonTxType);
return new JsonTx(tx.getId(),
tx.getBlockHeight(),
tx.getBlockHash(),
tx.getTime(),
getJsonTxInputs(daoStateService, tx),
getJsonTxOutputs(daoStateService, tx),
jsonTxType,
jsonTxTypeDisplayString,
tx.getBurntFee(),
tx.getInvalidatedBsq(),
tx.getUnlockBlockHeight());
}

private static List<JsonTxInput> getJsonTxInputs(DaoStateService daoStateService, Tx tx) {
return tx.getTxInputs().stream()
.map(txInput -> {
Optional<TxOutput> optionalTxOutput = daoStateService.getConnectedTxOutput(txInput);
if (optionalTxOutput.isPresent()) {
TxOutput connectedTxOutput = optionalTxOutput.get();
boolean isBsqTxOutputType = daoStateService.isBsqTxOutputType(connectedTxOutput);
return new JsonTxInput(txInput.getConnectedTxOutputIndex(),
txInput.getConnectedTxOutputTxId(),
connectedTxOutput.getValue(),
isBsqTxOutputType,
connectedTxOutput.getAddress(),
tx.getTime());
} else {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

private static List<JsonTxOutput> getJsonTxOutputs(DaoStateService daoStateService, Tx tx) {
JsonTxType jsonTxType = getJsonTxType(tx);
String jsonTxTypeDisplayString = getJsonTxTypeDisplayString(jsonTxType);
return tx.getTxOutputs().stream()
.map(txOutput -> {
boolean isBsqTxOutputType = daoStateService.isBsqTxOutputType(txOutput);
long bsqAmount = isBsqTxOutputType ? txOutput.getValue() : 0;
long btcAmount = !isBsqTxOutputType ? txOutput.getValue() : 0;
PubKeyScript pubKeyScript = txOutput.getPubKeyScript();
JsonScriptPubKey scriptPubKey = pubKeyScript != null ? new JsonScriptPubKey(pubKeyScript) : null;
JsonSpentInfo spentInfo = daoStateService.getSpentInfo(txOutput).map(JsonSpentInfo::new).orElse(null);
JsonTxOutputType txOutputType = JsonTxOutputType.valueOf(txOutput.getTxOutputType().name());
int lockTime = txOutput.getLockTime();
BaseEncoding HEX = BaseEncoding.base16().lowerCase();
String opReturn = txOutput.getOpReturnData() != null ? HEX.encode(txOutput.getOpReturnData()) : null;
boolean isUnspent = daoStateService.isUnspent(txOutput.getKey());
return new JsonTxOutput(tx.getId(),
txOutput.getIndex(),
bsqAmount,
btcAmount,
tx.getBlockHeight(),
isBsqTxOutputType,
tx.getBurntFee(),
tx.getInvalidatedBsq(),
txOutput.getAddress(),
scriptPubKey,
spentInfo,
tx.getTime(),
jsonTxType,
jsonTxTypeDisplayString,
txOutputType,
txOutputType.getDisplayString(),
opReturn,
lockTime,
isUnspent
);
})
.collect(Collectors.toList());
}

private static String getJsonTxTypeDisplayString(JsonTxType jsonTxType) {
return jsonTxType != null ? jsonTxType.getDisplayString() : "";
}

private static JsonTxType getJsonTxType(Tx tx) {
TxType txType = tx.getTxType();
return txType != null ? JsonTxType.valueOf(txType.name()) : null;
}
}
Loading

0 comments on commit 20e7a38

Please sign in to comment.