mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-11-02 21:47:18 +00:00
Add a couple of methods to TransactionConfidence to get depth in chain measured in blocks and work done. Add example of usage to PingService. Still not quite there yet.
This commit is contained in:
committed by
Miron Cuperman
parent
0a4dbb77cf
commit
5126745e01
@@ -301,6 +301,13 @@ public class BlockChain {
|
||||
return currentChainCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the height of the best known chain, convenience for <tt>getChainHead().getHeight()</tt>.
|
||||
*/
|
||||
public int getBestChainHeight() {
|
||||
return getChainHead().getHeight();
|
||||
}
|
||||
|
||||
enum NewBlockType {
|
||||
BEST_CHAIN,
|
||||
SIDE_CHAIN
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import com.google.bitcoin.store.BlockStoreException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -123,4 +126,48 @@ public class TransactionConfidence implements Serializable {
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Depth in the chain is an approximation of how much time has elapsed since the transaction has been confirmed. On
|
||||
* average there is supposed to be a new block every 10 minutes, but the actual rate may vary. The reference
|
||||
* (Satoshi) implementation considers a transaction impractical to reverse after 6 blocks, but as of EOY 2011 network
|
||||
* security is high enough that often only one block is considered enough even for high value transactions. For low
|
||||
* value transactions like songs, or other cheap items, no blocks at all may be necessary.<p>
|
||||
*
|
||||
* If the transaction appears in the top block, the depth is one. The result may be < 0 if the transaction isn't
|
||||
* in the best chain or wasn't seen in any blocks at all.
|
||||
*
|
||||
* @param chain a {@link BlockChain} instance.
|
||||
* @return depth, or {@link TransactionConfidence#NOT_IN_BEST_CHAIN} or {@link TransactionConfidence#NOT_SEEN_IN_CHAIN}
|
||||
*/
|
||||
public int getDepthInBlocks(BlockChain chain) {
|
||||
int height = getAppearedAtChainHeight();
|
||||
switch (height) {
|
||||
case NOT_IN_BEST_CHAIN: return NOT_IN_BEST_CHAIN;
|
||||
case NOT_SEEN_IN_CHAIN: return NOT_SEEN_IN_CHAIN;
|
||||
default: return chain.getBestChainHeight() - height + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the estimated amount of work (number of hashes performed) on this transaction. Work done is a measure of
|
||||
* security that is related to depth in blocks, but more predictable: the network will always attempt to produce six
|
||||
* blocks per hour by adjusting the difficulty target. So to know how much real computation effort is needed to
|
||||
* reverse a transaction, counting blocks is not enough.
|
||||
*
|
||||
* @param chain
|
||||
* @return estimated number of hashes needed to reverse the transaction. Zero if not seen in any block yet.
|
||||
*/
|
||||
public BigInteger getWorkDone(BlockChain chain) throws BlockStoreException {
|
||||
BigInteger work = BigInteger.ZERO;
|
||||
int depth = getDepthInBlocks(chain);
|
||||
if (depth == NOT_IN_BEST_CHAIN || depth == NOT_SEEN_IN_CHAIN)
|
||||
return BigInteger.ZERO;
|
||||
StoredBlock block = chain.getChainHead();
|
||||
for (; depth > 0; depth--) {
|
||||
work = work.add(block.getChainWork());
|
||||
block = block.getPrev(chain.blockStore);
|
||||
}
|
||||
return work;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.google.bitcoin.examples;
|
||||
import com.google.bitcoin.core.*;
|
||||
import com.google.bitcoin.discovery.DnsDiscovery;
|
||||
import com.google.bitcoin.store.BlockStore;
|
||||
import com.google.bitcoin.store.BlockStoreException;
|
||||
import com.google.bitcoin.store.BoundedOverheadBlockStore;
|
||||
import com.google.bitcoin.utils.BriefLogFormatter;
|
||||
|
||||
@@ -27,6 +28,7 @@ import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -56,22 +58,23 @@ public class PingService {
|
||||
BriefLogFormatter.init();
|
||||
|
||||
String peerHost = args.length > 0 ? args[0] : null;
|
||||
int peerPort = args.length > 1 ? Integer.parseInt(args[1]) : 0;
|
||||
int peerPort = args.length > 1 ? Integer.parseInt(args[1]) : NetworkParameters.prodNet().port;
|
||||
|
||||
boolean testNet = peerPort == NetworkParameters.testNet().port;
|
||||
boolean testNet = peerPort != NetworkParameters.prodNet().port;
|
||||
final NetworkParameters params = testNet ? NetworkParameters.testNet() : NetworkParameters.prodNet();
|
||||
String filePrefix = testNet ? "pingservice-testnet" : "pingservice-prodnet";
|
||||
|
||||
// Try to read the wallet from storage, create a new one if not possible.
|
||||
Wallet wallet;
|
||||
Wallet w;
|
||||
final File walletFile = new File(filePrefix + ".wallet");
|
||||
try {
|
||||
wallet = Wallet.loadFromFile(walletFile);
|
||||
w = Wallet.loadFromFile(walletFile);
|
||||
} catch (IOException e) {
|
||||
wallet = new Wallet(params);
|
||||
wallet.keychain.add(new ECKey());
|
||||
wallet.saveToFile(walletFile);
|
||||
w = new Wallet(params);
|
||||
w.keychain.add(new ECKey());
|
||||
w.saveToFile(walletFile);
|
||||
}
|
||||
final Wallet wallet = w;
|
||||
// Fetch the first key in the wallet (should be the only key).
|
||||
ECKey key = wallet.keychain.get(0);
|
||||
|
||||
@@ -83,15 +86,13 @@ public class PingService {
|
||||
|
||||
// Connect to the localhost node. One minute timeout since we won't try any other peers
|
||||
System.out.println("Connecting ...");
|
||||
BlockChain chain = new BlockChain(params, wallet, blockStore);
|
||||
final BlockChain chain = new BlockChain(params, wallet, blockStore);
|
||||
|
||||
final PeerGroup peerGroup = new PeerGroup(params, chain);
|
||||
// Download headers only until a day ago.
|
||||
peerGroup.setFastCatchupTimeSecs((new Date().getTime() / 1000) - (60 * 60 * 24));
|
||||
|
||||
if (peerHost != null) {
|
||||
// TEMP!
|
||||
peerGroup.addAddress(new PeerAddress(InetAddress.getLocalHost(), peerPort));
|
||||
peerGroup.addAddress(new PeerAddress(InetAddress.getByName(peerHost), peerPort));
|
||||
} else {
|
||||
peerGroup.addPeerDiscovery(new DnsDiscovery(params));
|
||||
@@ -100,6 +101,25 @@ public class PingService {
|
||||
peerGroup.addWallet(wallet);
|
||||
peerGroup.start();
|
||||
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
|
||||
super.onBlocksDownloaded(peer, block, blocksLeft);
|
||||
|
||||
Set<Transaction> transactions = wallet.getTransactions(false, false);
|
||||
if (transactions.size() == 0) return;
|
||||
System.out.println("Confidences of wallet transactions:");
|
||||
for (Transaction tx : transactions) {
|
||||
System.out.println(tx);
|
||||
try {
|
||||
System.out.println("Work done: " + tx.getConfidence().getWorkDone(chain).toString());
|
||||
} catch (BlockStoreException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We want to know when the balance changes.
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
@Override
|
||||
|
||||
@@ -294,6 +294,10 @@ public class ChainSplitTests {
|
||||
assertEquals(2, txns.size());
|
||||
assertEquals(1, txns.get(0).getConfidence().getAppearedAtChainHeight());
|
||||
assertEquals(2, txns.get(1).getConfidence().getAppearedAtChainHeight());
|
||||
assertEquals(1, txns.get(1).getConfidence().getDepthInBlocks(chain));
|
||||
assertEquals(2, txns.get(0).getConfidence().getDepthInBlocks(chain));
|
||||
assertEquals(10, txns.get(0).getConfidence().getWorkDone(chain).intValue());
|
||||
assertEquals(6, txns.get(1).getConfidence().getWorkDone(chain).intValue());
|
||||
// We now have the following chain:
|
||||
// genesis -> b1 -> b2
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user