Guest User

Untitled

a guest
Mar 24th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.86 KB | None | 0 0
  1. import Block from 'classes/Block';
  2. import BlockModel from 'models/Block';
  3. import find from 'lodash/find';
  4. import { verifyUnlock } from 'utils/verifySignature';
  5.  
  6. const COIN = 100000000;
  7. const COINBASE_REWARD = 50 * COIN;
  8.  
  9. export async function areBlocksValid(blocks) {
  10. for (let i = 1; i < blocks.length; i++) {
  11. const isValidBlk = await isBlockValid(blocks[i], blocks[i-1]);
  12. if (!isValidBlk) {
  13. return false;
  14. }
  15. }
  16. return true;
  17. }
  18.  
  19. export async function isBlockValid(block, prevBlock) {
  20. // check transactions
  21. const { txs } = block;
  22. for (let i = 0; i < txs.length; i++) {
  23. const isValidTx = await isTxValid(txs[i]);
  24. if (!isValidTx) {
  25. return false;
  26. }
  27. }
  28. // check nonce
  29. const target = Math.pow(2, 256 - block.difficulty);
  30. if (parseInt(block.hash, 16) > target) {
  31. console.log('> Incorrect nonce: ', block.hash);
  32. return false;
  33. }
  34. return true;
  35. }
  36.  
  37. export async function isTxValid(tx) {
  38. // verify has "vin" and "vout" as Arrays
  39. if (!tx.vin || !tx.vin.length || !tx.vout || !tx.vout.length) {
  40. return false;
  41. }
  42. let isCoinbase = false;
  43. let txinValue = 0;
  44. let txoutValue = 0;
  45. // check inputs
  46. for (let i = 0; i < tx.vin.length; i++) {
  47. const txin = tx.vin[i];
  48. if (txin.prevout === 'COINBASE') {
  49. // make sure only one coinbase tx
  50. if (tx.vout.length > 1 || tx.vin.length > 1 || tx.vout[i].nValue > COINBASE_REWARD) {
  51. // ensure coinbase is not greater than agreed on reward
  52. return false;
  53. }
  54. return true;
  55. }
  56. // validate regular input
  57. if (!txin.prevout || !txin.scriptSig || typeof txin.n != 'number') {
  58. return false;
  59. }
  60. // find previous UTXO
  61. let prevTxBlock = await BlockModel.findOne({ 'txs.hash': txin.prevout });
  62. if (!prevTxBlock) {
  63. return false;
  64. }
  65. let prevTx = find(prevTxBlock.txs, ({ hash }) => hash === txin.prevout);
  66. if (!prevTx) {
  67. return false;
  68. }
  69. txinValue += prevTx.vout[txin.n].nValue;
  70. // ensure that prevout is UXTO - prevent double spending
  71. let alreadySpentTxs = await BlockModel.find({ "txs.vin.prevout": txin.prevout });
  72. if (alreadySpentTxs.length > 1) {
  73. return false;
  74. }
  75. // verify signature
  76. let publicKeyScript = prevTx.vout[txin.n].scriptPubKey;
  77. let txid = prevTx.hash;
  78. let [ publicKey, scriptSig ] = txin.scriptSig.split(' ');
  79. let isVerified = verifyUnlock(txid, prevTx.vout[txin.n].scriptPubKey, publicKey, scriptSig);
  80. if (!isVerified) {
  81. return false;
  82. }
  83. // check transaction outputs
  84. for (let i = 0; i < tx.vout.length; i++) {
  85. let txout = tx.vout[i];
  86. if (typeof txout.nValue != 'number' || typeof txout.scriptPubKey != 'string') {
  87. return false;
  88. }
  89. txoutValue += txout.nValue;
  90. }
  91. // check that inputs are not less than outputs
  92. let totalFees = txinValue - txoutValue;
  93. if (totalFees < 0) {
  94. return false;
  95. }
  96. return true;
  97. }
  98. }
Add Comment
Please, Sign In to add comment