项目集合

signum-node: https://github.com/signum-network/signum-node.git
signum-miner: https://github.com/signum-network/signum-miner.git
signum-plot:https://github.com/signum-network/signum-plotter.git
btdex: https://github.com/btdex/btdex.git

signum-node是一个全节点,存放有全部的区块信息
signum-miner实现挖矿逻辑,
btdex 是挖矿界面,会调用signum-miner实现挖矿逻辑。

class MineThread extends Thread {public void run() {try {String cmd = minerFile.getAbsolutePath() + " -c " + MINER_CONFIG_FILE;logger.info("Running miner with '{}'", cmd);minerProcess = Runtime.getRuntime().exec(cmd, null, minerFile.getParentFile());InputStream stdIn = minerProcess.getInputStream();InputStreamReader isr = new InputStreamReader(stdIn);BufferedReader br = new BufferedReader(isr);while (minerProcess.isAlive()) {String line = br.readLine();if(line != null)addToConsole(MINER_APP, line);}mining = false;minerFile.delete();} catch (Exception e) {e.printStackTrace();}}};

btdex 调用miner下的二进制文件signum-miner,signum-miner实现具体的挖矿流程

create_cpu_worker_task->hash->find_best_deadline_rust

pub fn find_best_deadline_rust(data: &[u8],number_of_nonces: u64,gensig: &[u8; 32],) -> (u64, u64) {let mut best_deadline = u64::MAX;let mut best_offset = 0;for i in 0..number_of_nonces as usize {let result =shabal256_deadline_fast(&data[i * SCOOP_SIZE..i * SCOOP_SIZE + SCOOP_SIZE], &gensig);if result < best_deadline {best_deadline = result;best_offset = i;}}(best_deadline, best_offset as u64)}

plot

String plotterName = "signum-plotter";if(OS.isWindows())plotterName += ".exe";else if(OS.isMacOsX())plotterName += ".app";plotterFile = new File(TMP_DIR, plotterName);if (!plotterFile.exists() || plotterFile.length() == 0) { InputStream link = (getClass().getResourceAsStream("/plotter/" + plotterName)); try {logger.info("Copying ploter to {}", plotterFile.getAbsolutePath());Files.copy(link, plotterFile.getAbsoluteFile().toPath());if(!OS.isWindows())plotterFile.setExecutable(true);} catch (IOException ex) {ex.printStackTrace();Toast.makeText((JFrame) SwingUtilities.getWindowAncestor(this), ex.getMessage(), Toast.Style.ERROR).display();plotting = false;return;}}PlotThread plotThread = new PlotThread();plotThread.start();

出块和共识过程

1 signum-miner扫描磁盘找到合适的nonce和deadline,向节点提交nonce

let mut query = format!("requestType=submitNonce&accountId={}&nonce={}&secretPhrase={}&blockheight={}",submission_data.account_id, submission_data.nonce, secret_phrase, submission_data.height);// If we don't have a secret phrase then we most likely talk to a pool or a proxy.// Both can make use of the deadline, e.g. a proxy won't validate deadlines but still// needs to rank the deadlines.// The best thing is that legacy proxies use the unadjusted deadlines so...// yay another parameter!if secret_phrase == "" {query += &format!("&deadline={}", submission_data.deadline_unadjusted);}

2 节点维护了generators结合,这个集合存储使用这个节点出块的accountID,私钥,块高,这个数据结构可以根据nonce计算deadline节点收到submitNonce后,会调用addNonce方法

/src/brs/GeneratorImpl.java private final Long accountId;private final String secretPhrase;private final byte[] publicKey;private final BigInteger deadline;private final BigInteger hit;private final long baseTarget;private final long nonce;private final long block;
/src/brs/GeneratorImpl.javapublic GeneratorState addNonce(String secretPhrase, Long nonce, byte[] publicKey) {byte[] publicKeyHash = Crypto.sha256().digest(publicKey);long id = Convert.fullHashToId(publicKeyHash);GeneratorStateImpl generator = new GeneratorStateImpl(secretPhrase, nonce, publicKey, id);GeneratorStateImpl curGen = generators.get(id);if (curGen == null || generator.getBlock() > curGen.getBlock() || generator.getDeadline().compareTo(curGen.getDeadline()) < 0) {generators.put(id, generator);listeners.notify(generator, Event.NONCE_SUBMITTED);if (logger.isDebugEnabled()) {logger.debug("Account {} started mining, deadline {} seconds", Convert.toUnsignedLong(id), generator.getDeadline());}} else {if (logger.isDebugEnabled()) {logger.debug("Account {} already has a better nonce", Convert.toUnsignedLong(id));}}return generator;}

3 GeneratorImpl有一个定时任务,每0.5秒跑一次,使用generator出块
出块调用的方法是generator.getValue().forge(blockchainProcessor);

 private Runnable generateBlockThread(BlockchainProcessor blockchainProcessor) {return () -> {if (blockchainProcessor.isScanning()) {return;}try {long currentBlock = blockchain.getLastBlock().getHeight();Iterator<Entry<Long, GeneratorStateImpl>> it = generators.entrySet().iterator();while (it.hasNext() && !Thread.currentThread().isInterrupted() && ThreadPool.running.get()) {Entry<Long, GeneratorStateImpl> generator = it.next();if (currentBlock < generator.getValue().getBlock()) {generator.getValue().forge(blockchainProcessor);} else {it.remove();}}} catch (BlockchainProcessor.BlockNotAcceptedException e) {logger.debug("Error in block generation thread", e);}};}

4 forge方法最终调用的是BlockchainProcessor的generateBlock方法,generateBlock会调用pushBlock方法,
pushBlock会验证执行交易,并且把block推到其他peerr

出块和向其他peer推送交易

logger.debug("Successfully pushed {} (height {})", block.getId(), block.getHeight());statisticsManager.blockAdded();blockListeners.notify(block, Event.BLOCK_PUSHED);if (block.getTimestamp() >= timeService.getEpochTime() - MAX_TIMESTAMP_DIFFERENCE) {Peers.sendToSomePeers(block);}

BlockchainProcessorImpl中调度多个定时任务
getMoreBlocksThread:获取更多block
blockImporterThread:使用区块,调用verifyGenerationSignature会使用到setPocTime
pocVerificationThread:验证区块->blockService.preVerify->setPocTime

1 GeneratorImpl.calculateHit计算Scoop number