Skip to content

Commit

Permalink
- changed PoW signing window
Browse files Browse the repository at this point in the history
- consensus recovery mode
- improved PoW signature miner
- minor fixes
  • Loading branch information
IxiAngel committed Oct 24, 2024
1 parent 737d638 commit c674bab
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 30 deletions.
3 changes: 3 additions & 0 deletions IxianDLT/API/APIServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,19 @@ private Dictionary<string, string> blockToJsonDictionary(Block block)
blockData.Add("Compacted Sigs", block.compactedSigs.ToString());
blockData.Add("Signature count", block.signatures.Count.ToString());
blockData.Add("Required Signature count", Node.blockChain.getRequiredConsensusFromStorage(block.blockNum).ToString());

var totalSignerDifficulty = Node.blockChain.getBlockTotalSignerDifficulty(block.blockNum);
if (totalSignerDifficulty == null)
{
totalSignerDifficulty = block.getTotalSignerDifficulty();
}
blockData.Add("Total Signer Difficulty", totalSignerDifficulty.ToString());

if (block.version >= BlockVer.v10)
{
blockData.Add("Required Signer Difficulty", Node.blockChain.getRequiredSignerDifficulty(block, true).ToString());
}

blockData.Add("Transaction count", block.transactions.Count.ToString());
blockData.Add("Transaction amount", TransactionPool.getTotalTransactionsValueInBlock(block).ToString());
blockData.Add("Total fees", block.totalFee.ToString());
Expand Down
22 changes: 17 additions & 5 deletions IxianDLT/Block/BlockChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,11 @@ public IxiNumber getBlockTotalSignerDifficulty(ulong blockNum)
{
return bh.Value.totalSignerDifficulty;
}
var hashAndTotalSignerDiff = Node.storage.getBlockTotalSignerDifficulty(blockNum);
if (hashAndTotalSignerDiff.blockChecksum != null && hashAndTotalSignerDiff.totalSignerDifficulty != null)
var hashAndSignerDiffs = Node.storage.getBlockTotalSignerDifficulty(blockNum);
if (hashAndSignerDiffs.blockChecksum != null && hashAndSignerDiffs.totalSignerDifficulty != null)
{
cacheBlockSignerDifficulty(blockNum, hashAndTotalSignerDiff.blockChecksum, new IxiNumber(hashAndTotalSignerDiff.totalSignerDifficulty));
return hashAndTotalSignerDiff.totalSignerDifficulty;
cacheBlockSignerDifficulty(blockNum, hashAndSignerDiffs.blockChecksum, new IxiNumber(hashAndSignerDiffs.totalSignerDifficulty));
return hashAndSignerDiffs.totalSignerDifficulty;
}
}
}
Expand Down Expand Up @@ -894,6 +894,12 @@ private IxiNumber calculateRequiredSignerDifficulty_v2(long curBlockTimestamp)
ulong blockCount = 0;
ulong blocksToUseForDifficultyCalculation = blockNum - lastDiffChangeSuperblock.blockNum;

IxiNumber maxSingleBlockDifficulty = null;
if (lastDiffChangeSuperblock != null && lastDiffChangeSuperblock.signerBits > 0)
{
maxSingleBlockDifficulty = SignerPowSolution.bitsToDifficulty(lastDiffChangeSuperblock.signerBits) * 4;
}

for (ulong i = 0; i < blocksToUseForDifficultyCalculation; i++)
{
ulong consensusBlockNum = blockNum - i - blockOffset;
Expand All @@ -904,6 +910,12 @@ private IxiNumber calculateRequiredSignerDifficulty_v2(long curBlockTimestamp)
break;
}

// Smooth-out difficulty spikes
if (maxSingleBlockDifficulty != null
&& blockTotalSignerDifficulty > maxSingleBlockDifficulty)
{
blockTotalSignerDifficulty = maxSingleBlockDifficulty;
}
totalDifficulty += blockTotalSignerDifficulty;
blockCount++;
}
Expand All @@ -922,7 +934,7 @@ private IxiNumber calculateRequiredSignerDifficulty_v2(long curBlockTimestamp)
return ConsensusConfig.minBlockSignerPowDifficulty;
}

IxiNumber newDifficulty = totalDifficulty / blockCount;
IxiNumber newDifficulty = totalDifficulty / ConsensusConfig.difficultyAdjustmentExpectedBlockCount;

return newDifficulty;
}
Expand Down
92 changes: 79 additions & 13 deletions IxianDLT/Block/BlockProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ public void onUpdate()
if (timeSinceLastBlock.TotalSeconds > (blockGenerationInterval * 4) + randomInt / 100) // no block for 4 block times + random seconds, we don't want all nodes sending at once
{
generateNextBlock = true;
block_version = Node.blockChain.getLastBlockVersion();
}
else
{
Expand All @@ -214,7 +213,6 @@ public void onUpdate()
blacklistBlock(localNewBlock);
localNewBlock = null;
lastBlockStartTime = DateTime.UtcNow.AddSeconds(-blockGenerationInterval * 10);
block_version = Node.blockChain.getLastBlockVersion();
sleep = true;
if (forkedFlag)
{
Expand Down Expand Up @@ -769,15 +767,15 @@ public void onBlockReceived(Block b, RemoteEndpoint endpoint = null)

public BlockVerifyStatus verifyBlockBasic(Block b, bool verify_sig = true, RemoteEndpoint endpoint = null)
{
// TODO omega remove bottom if section after v11 upgrade
// TODO omega remove bottom if section after v12 upgrade
if (!IxianHandler.isTestNet)
{
// upgrade to v11 at exactly block 4100000
if (b.blockNum < 4100000 && b.version >= BlockVer.v11)
// upgrade to v12 at exactly block 4650000
if (b.blockNum < 4650000 && b.version >= BlockVer.v12)
{
return BlockVerifyStatus.Invalid;
}
if (b.blockNum >= 4100000 && b.version < BlockVer.v11)
if (b.blockNum >= 4650000 && b.version < BlockVer.v12)
{
return BlockVerifyStatus.Invalid;
}
Expand Down Expand Up @@ -1746,7 +1744,8 @@ public bool hasRequiredSignatureCount(Block block)
if (block.blockNum > 6 && block.version >= BlockVer.v5)
{
int required_consensus_count = Node.blockChain.getRequiredConsensus(block.blockNum);
if (frozen_sig_count < required_consensus_count)
if (frozen_sig_count < required_consensus_count
&& !isBlockchainRecoveryMode(block.blockNum, block.timestamp, frozen_sig_count))
{
//Logging.info("Block {0} has less than required signatures ({1} < {2}).", block.blockNum, frozen_sig_count, required_consensus_count);
return false;
Expand Down Expand Up @@ -1774,17 +1773,19 @@ public bool verifyBlockSignatures(Block block, RemoteEndpoint endpoint)
int required_consensus_count = Node.blockChain.getRequiredConsensus(block.blockNum);

// verify sig count
if (frozen_sig_count < required_consensus_count)
if (frozen_sig_count < required_consensus_count
&& !isBlockchainRecoveryMode(block.blockNum, block.timestamp, frozen_sig_count))
{
Logging.info("Block {0} has less than required signatures ({1} < {2}).", block.blockNum, frozen_sig_count, required_consensus_count);
return false;
}

IxiNumber frozen_sig_difficulty = block.getTotalSignerDifficulty();
IxiNumber required_signer_difficulty = null;

if (block.version >= BlockVer.v10 && IxianHandler.getBlockHeader(block.blockNum - 1).version >= BlockVer.v10)
{
IxiNumber required_signer_difficulty = Node.blockChain.getRequiredSignerDifficulty(block, true);
required_signer_difficulty = Node.blockChain.getRequiredSignerDifficulty(block, true);

// verify sig difficulty
if (frozen_sig_difficulty < required_signer_difficulty)
Expand All @@ -1803,7 +1804,8 @@ public bool verifyBlockSignatures(Block block, RemoteEndpoint endpoint)
if (required_consensus_count > 2)
{
// verify if over 50% signatures are from the previous block
if (required_sigs.Count() < (required_consensus_count / 2) + 1)
if (required_sigs.Count < (required_consensus_count / 2) + 1
&& !handleBlockchainRecoveryMode(block, required_sigs.Count, frozen_sig_count, frozen_sig_difficulty, required_signer_difficulty))
{
Logging.warn("Block {0} has less than 50% + 1 required signers from previous block {1} < {2}.", block.blockNum, required_sigs.Count(), (required_consensus_count / 2) + 1);
return false;
Expand Down Expand Up @@ -1934,6 +1936,7 @@ public bool freezeSignatures(Block target_block)
return false;
}

int required_signature_count = frozen_block_sigs.Count;
int sig_count = frozen_block_sigs.Count;

lock (target_block.signatures)
Expand Down Expand Up @@ -1993,7 +1996,8 @@ public bool freezeSignatures(Block target_block)
}
}

if (frozen_block_sigs.Count < required_consensus_count_adjusted)
if (frozen_block_sigs.Count < required_consensus_count_adjusted
&& !handleBlockchainRecoveryMode(target_block, required_signature_count, frozen_block_sigs.Count, frozen_block_sigs_difficulty, required_difficulty_adjusted))
{
Logging.warn("Error freezing signatures of target block #{0} {1}, cannot freeze enough signatures to pass consensus, difficulty: {2} < {3} count: {4} < {5}.", target_block.blockNum, Crypto.hashToString(target_block.blockChecksum), frozen_block_sigs_difficulty, required_difficulty_adjusted, frozen_block_sigs.Count, required_consensus_count_adjusted);
return false;
Expand Down Expand Up @@ -2032,6 +2036,67 @@ public bool freezeSignatures(Block target_block)
}
}

private bool isBlockchainRecoveryMode(ulong blockNum, long blockTimestamp, int totalBlockSignatures)
{
Block prevBlock = IxianHandler.getBlockHeader(blockNum - 1);
if (prevBlock == null || prevBlock.timestamp + ConsensusConfig.blockChainRecoveryTimeout > blockTimestamp)
{
return false;
}

if (totalBlockSignatures < 3)
{
return false;
}

return true;
}

private bool handleBlockchainRecoveryMode(Block curBlock, int requiredSignatureCount, int totalBlockSignatures, IxiNumber totalSignerDifficulty, IxiNumber requiredSignerDifficultyAdjusted)
{
if (!isBlockchainRecoveryMode(curBlock.blockNum, curBlock.timestamp, totalBlockSignatures))
{
return false;
}

int requiredConsensus = Node.blockChain.getRequiredConsensus(curBlock.blockNum, false);
int requiredConsensusAdj = Node.blockChain.getRequiredConsensus(curBlock.blockNum, true);

int missingRequiredSigs = ((requiredConsensus / 2 ) + 1) - requiredSignatureCount;
int missingSigs = requiredConsensusAdj - totalBlockSignatures;

// no missing sigs, no need for recovery mode
if (missingRequiredSigs <= 0 && missingSigs <= 0)
{
return false;
}

// missing sigs and no block for a period of time, run recovery checks

IxiNumber recoveryRequiredSignerDifficulty = 0;
if (missingRequiredSigs > 0)
{
recoveryRequiredSignerDifficulty = missingRequiredSigs * requiredSignerDifficultyAdjusted * ConsensusConfig.blockChainRecoveryMissingRequiredSignerRatio / 100; // TODO requiredSignerDifficultyAdjusted or requiredSignerDifficulty
if (totalSignerDifficulty < recoveryRequiredSignerDifficulty)
{
return false;
}
}

if (missingSigs > 0)
{
if (totalSignerDifficulty < recoveryRequiredSignerDifficulty + (missingSigs * IxianHandler.getMinSignerPowDifficulty(curBlock.blockNum, curBlock.timestamp))) // TODO Add ratio?
{
return false;
}
}

Logging.warn("Recovery mode activated for block #{0} {1}, missing required sigs:{2}, missing sigs: {3}, cur time: {4}, block time: {5}, total signer difficulty: {6}, requiredSignerDifficultyAdjusted: {7}.",
curBlock.blockNum, Crypto.hashToString(curBlock.calculateChecksum()), missingRequiredSigs, missingSigs, Clock.getNetworkTimestamp(), curBlock.timestamp, totalSignerDifficulty, requiredSignerDifficultyAdjusted);

return true;
}

public bool acceptLocalNewBlock()
{
bool block_accepted = false;
Expand Down Expand Up @@ -3154,7 +3219,7 @@ public void generateNewBlock(int block_version)
localNewBlock.setRegNameStateChecksum(Node.regNameState.calculateRegNameStateChecksum(localNewBlock.blockNum));
}

Logging.info("While generating new block: Node's blockversion: {0}", IxianHandler.getLastBlockVersion());
Logging.info("While generating new block: Node's blockversion: {0}", localNewBlock.version);
Logging.info("While generating new block: WS Checksum: {0}", Crypto.hashToString(localNewBlock.walletStateChecksum));
if (localNewBlock.regNameStateChecksum != null)
{
Expand Down Expand Up @@ -3630,7 +3695,8 @@ public byte[] getSignatureFreeze(Block freezing_block, int block_ver)
if (block_ver >= BlockVer.v5 && freezing_block.blockNum > 11)
{
bool froze_signatures = freezeSignatures(target_block);
if(!froze_signatures || target_block.getFrozenSignatureCount() < Node.blockChain.getRequiredConsensus(target_block.blockNum))
if(!froze_signatures
|| (target_block.getFrozenSignatureCount() < Node.blockChain.getRequiredConsensus(target_block.blockNum) && !isBlockchainRecoveryMode(target_block.blockNum, target_block.timestamp, target_block.getFrozenSignatureCount())))
{
BlockProtocolMessages.broadcastGetBlock(target_block.blockNum);
if(froze_signatures)
Expand Down
8 changes: 4 additions & 4 deletions IxianDLT/Meta/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ public static string dataFolderBlocks
public static ulong forceSyncToBlock = 0;

// Read-only values
public static readonly string version = "xdc-0.9.2d"; // DLT Node version
public static readonly string version = "xdc-0.9.3-dev"; // DLT Node version

public static readonly string checkVersionUrl = "https://www.ixian.io/update.txt";
public static readonly int checkVersionSeconds = 6 * 60 * 60; // 6 hours

public static readonly ulong maxBlocksPerDatabase = 1000; // number of blocks to store in a single database file

public static readonly ulong nodeDeprecationBlock = 4600000 + (ulong)(new Random()).Next(50); // block height on which this version of Ixian DLT stops working on
public static readonly ulong nodeDeprecationBlock = 5000000 + (ulong)(new Random()).Next(50); // block height on which this version of Ixian DLT stops working on

public static readonly ulong saveWalletStateEveryBlock = ConsensusConfig.superblockInterval; // Saves wallet state every 1000 blocks

Expand All @@ -131,7 +131,7 @@ public static string dataFolderBlocks
// internal
public static bool changePass = false;

public static int maxBlockVersionToGenerate = 11;
public static int maxBlockVersionToGenerate = BlockVer.v12;

/// <summary>
/// Command to execute when a new block is accepted.
Expand Down
4 changes: 2 additions & 2 deletions IxianDLT/Meta/StatsConsoleScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void drawScreen()
int connectionsOut = NetworkClientManager.getConnectedClients(true).Count();
int connectionsIn = NetworkServer.getConnectedClients().Count();


string url = Config.apiBinds.First();

writeLine(" ██╗██╗ ██╗██╗ █████╗ ███╗ ██╗ ██████╗ ██╗ ████████╗ ");
writeLine(" ██║╚██╗██╔╝██║██╔══██╗████╗ ██║ ██╔══██╗██║ ╚══██╔══╝ ");
Expand All @@ -125,7 +125,7 @@ public void drawScreen()
writeLine(" ██║██╔╝ ██╗██║██║ ██║██║ ╚████║ ██████╔╝███████╗██║ ");
writeLine(" ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚═╝ ");
writeLine(" {0}", (Config.version + " BETA ").PadLeft(59));
writeLine(" {0}", ("http://localhost:" + Config.apiPort + "/"));
writeLine(" {0}", url);
writeLine("────────────────────────────────────────────────────────────");
if (update_avail)
{
Expand Down
Loading

0 comments on commit c674bab

Please sign in to comment.