Add bsq bonds

This commit is contained in:
chimp1984 2022-07-25 00:12:13 +02:00
parent ec00c9962f
commit 2628eea9db
No known key found for this signature in database
GPG Key ID: 9801B4EC591F90E3
9 changed files with 178 additions and 28 deletions

View File

@ -167,7 +167,7 @@ public class ProofOfBurnService implements DaoSetupService, DaoStateListener {
myProofOfBurnListService.addMyProofOfBurn(myProofOfBurn);
}
public byte[] getHashFromOpReturnData(Tx tx) {
public static byte[] getHashFromOpReturnData(Tx tx) {
return ProofOfBurnConsensus.getHashFromOpReturnData(tx.getLastTxOutput().getOpReturnData());
}

View File

@ -22,6 +22,7 @@ import bisq.core.app.TorSetup;
import bisq.core.app.misc.AppSetupWithP2PAndDAO;
import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.app.misc.ModuleForAppWithP2p;
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.user.Cookie;
@ -55,6 +56,8 @@ public class DaoNode extends ExecutableForAppWithP2p {
private Timer checkConnectionLossTime;
@Getter
private DaoStateService daoStateService;
@Getter
private BondedReputationRepository bondedReputationRepository;
public DaoNode() {
super("Bisq Dao Node", "bisq-dao-node", "bisq_dao_node", Version.VERSION);
@ -117,6 +120,7 @@ public class DaoNode extends ExecutableForAppWithP2p {
injector.getInstance(AppSetupWithP2PAndDAO.class).start();
daoStateService = injector.getInstance(DaoStateService.class);
bondedReputationRepository = injector.getInstance(BondedReputationRepository.class);
injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
@Override

View File

@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import bisq.daonode.endpoints.BondedReputationApi;
import bisq.daonode.endpoints.ProofOfBurnApi;
import bisq.daonode.error.CustomExceptionMapper;
import bisq.daonode.error.StatusException;
@ -54,6 +55,7 @@ public class DaoNodeRestApiApplication extends ResourceConfig {
.register(CustomExceptionMapper.class)
.register(StatusException.StatusExceptionMapper.class)
.register(ProofOfBurnApi.class)
.register(BondedReputationApi.class)
.register(SwaggerResolution.class);
daoNodeRestApiApplication.startServer(config.daoNodeApiUrl, config.daoNodeApiPort);
});
@ -62,6 +64,7 @@ public class DaoNodeRestApiApplication extends ResourceConfig {
@Getter
private final DaoNode daoNode;
private HttpServer httpServer;
public DaoNodeRestApiApplication() {

View File

@ -0,0 +1,48 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.daonode.dto;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Minimal data required for Bisq 2 bonded reputation use case.
* Need to be in sync with the Bisq 2 BondedReputationDto class.
*/
@Getter
@Slf4j
@Schema(title = "BondedReputation")
public class BondedReputationDto {
private long amount;
private long time;
private String hash;
private int blockHeight;
private int lockTime;
public BondedReputationDto(long amount, long time, String hash, int blockHeight, int lockTime) {
this.amount = amount;
this.time = time;
this.hash = hash;
this.blockHeight = blockHeight;
this.lockTime = lockTime;
}
}

View File

@ -24,23 +24,21 @@ import lombok.Getter;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Minimal data required for Bisq 2 reputation use case.
* Minimal data required for Bisq 2 proof of burn use case.
* Need to be in sync with the Bisq 2 ProofOfBurnDto class.
*/
@Getter
@Schema(title = "ProofOfBurn")
public class ProofOfBurnDto {
private final String txId;
private final long burnedAmount;
private final int blockHeight;
private final long amount;
private final long time;
private final String hash;
private final int blockHeight;
public ProofOfBurnDto(String txId, long burnedAmount, int blockHeight, long time, String hash) {
this.txId = txId;
this.burnedAmount = burnedAmount;
this.blockHeight = blockHeight;
public ProofOfBurnDto(long amount, long time, String hash, int blockHeight) {
this.amount = amount;
this.time = time;
this.hash = hash;
this.blockHeight = blockHeight;
}
}

View File

@ -0,0 +1,103 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.daonode.endpoints;
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.common.util.Hex;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import bisq.daonode.DaoNode;
import bisq.daonode.DaoNodeRestApiApplication;
import bisq.daonode.dto.BondedReputationDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
/**
* Endpoint for getting the bonded reputation data from a given block height.
* Used for reputation system in Bisq 2.
* <a href="http://localhost:8082/api/v1/bonded-reputation/get-bonded-reputation/0">Request with block height 0</a>
*/
@Slf4j
@Path("/bonded-reputation")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "Bonded reputation API")
public class BondedReputationApi {
private static final String DESC_BLOCK_HEIGHT = "The block height from which we request the bonded reputation data";
private final BondedReputationRepository bondedReputationRepository;
private final DaoStateService daoStateService;
public BondedReputationApi(@Context Application application) {
DaoNode daoNode = ((DaoNodeRestApiApplication) application).getDaoNode();
daoStateService = daoNode.getDaoStateService();
bondedReputationRepository = daoNode.getBondedReputationRepository();
}
@Operation(description = "Request the bonded reputation data")
@ApiResponse(responseCode = "200", description = "The bonded reputation data",
content = {@Content(mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(allOf = BondedReputationDto.class))}
)
@GET
@Path("get-bonded-reputation/{block-height}")
public List<BondedReputationDto> getBondedReputation(@Parameter(description = DESC_BLOCK_HEIGHT)
@PathParam("block-height")
int fromBlockHeight) {
return bondedReputationRepository.getActiveBonds().stream()
.map(bondedReputation -> {
Optional<Tx> optionalTx = daoStateService.getTx(bondedReputation.getLockupTxId());
if (optionalTx.isEmpty()) {
return null;
}
Tx tx = optionalTx.get();
int blockHeight = tx.getBlockHeight();
if (blockHeight >= fromBlockHeight) {
return new BondedReputationDto(bondedReputation.getAmount(),
tx.getTime(),
Hex.encode(bondedReputation.getBondedAsset().getHash()),
blockHeight,
bondedReputation.getLockTime()
);
} else {
return null;
}
}).filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

View File

@ -17,11 +17,10 @@
package bisq.daonode.endpoints;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.dao.governance.proofofburn.ProofOfBurnService;
import bisq.common.util.Hex;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@ -48,6 +47,11 @@ import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
/**
* Endpoint for getting the proof of burn data from a given block height.
* Used for reputation system in Bisq 2.
* <a href="http://localhost:8082/api/v1/proof-of-burn/get-proof-of-burn/0">Request with block height 0</a>
*/
@Slf4j
@Path("/proof-of-burn")
@Produces(MediaType.APPLICATION_JSON)
@ -69,23 +73,13 @@ public class ProofOfBurnApi {
@Path("get-proof-of-burn/{block-height}")
public List<ProofOfBurnDto> getProofOfBurn(@Parameter(description = DESC_BLOCK_HEIGHT)
@PathParam("block-height")
int blockHeight) {
int fromBlockHeight) {
return checkNotNull(daoNode.getDaoStateService()).getProofOfBurnTxs().stream()
.filter(tx -> tx.getBlockHeight() >= blockHeight)
.map(tx -> new ProofOfBurnDto(tx.getId(),
tx.getBurntBsq(),
tx.getBlockHeight(),
.filter(tx -> tx.getBlockHeight() >= fromBlockHeight)
.map(tx -> new ProofOfBurnDto(tx.getBurntBsq(),
tx.getTime(),
getHash(tx)))
Hex.encode(ProofOfBurnService.getHashFromOpReturnData(tx)),
tx.getBlockHeight()))
.collect(Collectors.toList());
}
// We strip out the version bytes
private String getHash(Tx tx) {
byte[] opReturnData = tx.getLastTxOutput().getOpReturnData();
if (opReturnData == null) {
return "";
}
return Hex.encode(Arrays.copyOfRange(opReturnData, 2, 22));
}
}

View File

@ -58,7 +58,7 @@ class MyProofOfBurnListItem {
amount = proofOfBurnService.getAmount(tx);
amountAsString = bsqFormatter.formatCoinWithCode(Coin.valueOf(amount));
txId = tx.getId();
hashAsHex = Utilities.bytesAsHexString(proofOfBurnService.getHashFromOpReturnData(tx));
hashAsHex = Utilities.bytesAsHexString(ProofOfBurnService.getHashFromOpReturnData(tx));
pubKey = Utilities.bytesAsHexString(proofOfBurnService.getPubKey(txId));
} else {
amount = 0;

View File

@ -45,7 +45,7 @@ class ProofOfBurnListItem {
amount = proofOfBurnService.getAmount(tx);
amountAsString = bsqFormatter.formatCoinWithCode(Coin.valueOf(amount));
txId = tx.getId();
hashAsHex = Utilities.bytesAsHexString(proofOfBurnService.getHashFromOpReturnData(tx));
hashAsHex = Utilities.bytesAsHexString(ProofOfBurnService.getHashFromOpReturnData(tx));
pubKey = Utilities.bytesAsHexString(proofOfBurnService.getPubKey(txId));
date = new Date(tx.getTime());
dateAsString = DisplayUtils.formatDateTime(date);