481 lines
13 KiB
JavaScript
481 lines
13 KiB
JavaScript
/*
|
|
* @project: TERA
|
|
* @version: Development (beta)
|
|
* @license: MIT (not for evil)
|
|
* @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com]
|
|
* Web: https://terafoundation.org
|
|
* Twitter: https://twitter.com/terafoundation
|
|
* Telegram: https://t.me/terafoundation
|
|
*/
|
|
|
|
var DELTA_LONG_MINING = 5000;
|
|
var BLOCKNUM_ALGO2 = 6560000;
|
|
var BLOCKNUM_HASH_NEW = 10195000;
|
|
var BLOCKNUM_TICKET_ALGO = 16070000;
|
|
if(typeof global === "object")
|
|
{
|
|
global.GetHashFromSeqAddr = GetHashFromSeqAddr;
|
|
global.CalcHashBlockFromSeqAddr = CalcHashBlockFromSeqAddr;
|
|
global.GetHashFromNum2 = GetHashFromNum2;
|
|
global.GetHashFromNum3 = GetHashFromNum3;
|
|
global.GetHashFromArrNum2 = GetHashFromArrNum2;
|
|
global.XORArr = XORArr;
|
|
global.GetHash = GetHash;
|
|
if(global.LOCAL_RUN || global.TEST_NETWORK)
|
|
{
|
|
BLOCKNUM_ALGO2 = 0;
|
|
if(global.TEST_NETWORK)
|
|
{
|
|
BLOCKNUM_HASH_NEW = 100;
|
|
BLOCKNUM_TICKET_ALGO = 0;
|
|
}
|
|
else
|
|
{
|
|
BLOCKNUM_HASH_NEW = 100;
|
|
BLOCKNUM_TICKET_ALGO = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function GetHashFromSeqAddr(SeqHash,AddrHash,BlockNum,PrevHash,MiningVer)
|
|
{
|
|
if(BlockNum < BLOCKNUM_ALGO2)
|
|
{
|
|
var Hash = shaarrblock2(SeqHash, AddrHash, BlockNum);
|
|
return {Hash:Hash, PowHash:Hash, Hash1:Hash, Hash2:Hash};
|
|
}
|
|
var MinerID = ReadUintFromArr(AddrHash, 0);
|
|
var Nonce0 = ReadUintFromArr(AddrHash, 6);
|
|
var Nonce1 = ReadUintFromArr(AddrHash, 12);
|
|
var Nonce2 = ReadUintFromArr(AddrHash, 18);
|
|
var DeltaNum1 = ReadUint16FromArr(AddrHash, 24);
|
|
var DeltaNum2 = ReadUint16FromArr(AddrHash, 26);
|
|
var PrevHashNum;
|
|
if(PrevHash)
|
|
{
|
|
PrevHashNum = ReadUint32FromArr(PrevHash, 28);
|
|
}
|
|
else
|
|
{
|
|
PrevHashNum = ReadUint32FromArr(AddrHash, 28);
|
|
}
|
|
var Data = GetHash(SeqHash, PrevHashNum, BlockNum, MinerID, Nonce0, Nonce1, Nonce2, DeltaNum1, DeltaNum2);
|
|
if(MiningVer)
|
|
{
|
|
if(AddrHash[17] !== MiningVer || AddrHash[23] !== MiningVer)
|
|
{
|
|
Data.PowHash = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255];
|
|
}
|
|
}
|
|
return Data;
|
|
};
|
|
|
|
function GetHash(BlockHash,PrevHashNum,BlockNum,Miner,Nonce0,Nonce1,Nonce2,DeltaNum1,DeltaNum2)
|
|
{
|
|
if(DeltaNum1 > DELTA_LONG_MINING)
|
|
DeltaNum1 = 0;
|
|
if(DeltaNum2 > DELTA_LONG_MINING)
|
|
DeltaNum2 = 0;
|
|
var HashBase = GetHashFromNum2(BlockNum, PrevHashNum);
|
|
var HashCurrent = GetHashFromArrNum2(BlockHash, Miner, Nonce0);
|
|
var HashNonce1 = GetHashFromNum3(BlockNum - DeltaNum1, Miner, Nonce1);
|
|
var HashNonce2 = GetHashFromNum3(BlockNum - DeltaNum2, Miner, Nonce2);
|
|
var Hash1 = XORArr(HashBase, HashNonce1);
|
|
var Hash2 = XORArr(HashCurrent, HashNonce2);
|
|
var Ret = {Hash:Hash2, Hash1:Hash1, Hash2:Hash2};
|
|
if(CompareArr(Hash1, Hash2) > 0)
|
|
{
|
|
Ret.PowHash = Hash1;
|
|
}
|
|
else
|
|
{
|
|
Ret.PowHash = Hash2;
|
|
}
|
|
if(BlockNum >= BLOCKNUM_HASH_NEW)
|
|
{
|
|
if(BlockNum >= BLOCKNUM_TICKET_ALGO)
|
|
Ret.Hash = sha3arr2(Hash1, Hash2);
|
|
else
|
|
Ret.Hash = shaarr2(Hash1, Hash2);
|
|
}
|
|
return Ret;
|
|
};
|
|
|
|
function CalcHashBlockFromSeqAddr(Block,PrevHash,MiningVer)
|
|
{
|
|
var Value = GetHashFromSeqAddr(Block.SeqHash, Block.AddrHash, Block.BlockNum, PrevHash, MiningVer);
|
|
Block.Hash = Value.Hash;
|
|
Block.PowHash = Value.PowHash;
|
|
};
|
|
|
|
function XORArr(Arr1,Arr2)
|
|
{
|
|
var Ret = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
for(var i = 0; i < 32; i++)
|
|
{
|
|
Ret[i] = Arr1[i] ^ Arr2[i];
|
|
}
|
|
return Ret;
|
|
};
|
|
|
|
function GetHashFromNum2(Value1,Value2)
|
|
{
|
|
var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
WriteUintToArrOnPos(MeshArr, Value1, 0);
|
|
WriteUintToArrOnPos(MeshArr, Value2, 6);
|
|
return sha3(MeshArr);
|
|
};
|
|
|
|
function GetHashFromArrNum2(Arr,Value1,Value2)
|
|
{
|
|
var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0];
|
|
WriteArrToArrOnPos(MeshArr, Arr, 0, 32);
|
|
WriteUintToArrOnPos(MeshArr, Value1, 32);
|
|
WriteUintToArrOnPos(MeshArr, Value2, 38);
|
|
return sha3(MeshArr);
|
|
};
|
|
|
|
function GetHashFromNum3(Value1,Value2,Value3)
|
|
{
|
|
var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
WriteUintToArrOnPos(MeshArr, Value1, 0);
|
|
WriteUintToArrOnPos(MeshArr, Value2, 6);
|
|
WriteUintToArrOnPos(MeshArr, Value3, 12);
|
|
return sha3(MeshArr);
|
|
};
|
|
|
|
function ReadUintFromArr(arr,len)
|
|
{
|
|
if(len === undefined)
|
|
{
|
|
len = arr.len;
|
|
arr.len += 6;
|
|
}
|
|
var value = (arr[len + 5] << 23) * 2 + (arr[len + 4] << 16) + (arr[len + 3] << 8) + arr[len + 2];
|
|
value = value * 256 + arr[len + 1];
|
|
value = value * 256 + arr[len];
|
|
return value;
|
|
};
|
|
|
|
function ReadUint32FromArr(arr,len)
|
|
{
|
|
if(len === undefined)
|
|
{
|
|
len = arr.len;
|
|
arr.len += 4;
|
|
}
|
|
var value = (arr[len + 3] << 23) * 2 + (arr[len + 2] << 16) + (arr[len + 1] << 8) + arr[len];
|
|
return value;
|
|
};
|
|
|
|
function ReadUint16FromArr(arr,len)
|
|
{
|
|
if(len === undefined)
|
|
{
|
|
len = arr.len;
|
|
arr.len += 2;
|
|
}
|
|
var value = (arr[len + 1] << 8) + arr[len];
|
|
return value;
|
|
};
|
|
|
|
function ReadArrFromArr(arr,length)
|
|
{
|
|
var Ret = [];
|
|
var len = arr.len;
|
|
for(var i = 0; i < length; i++)
|
|
{
|
|
Ret[i] = arr[len + i];
|
|
}
|
|
arr.len += length;
|
|
return Ret;
|
|
};
|
|
|
|
function WriteUintToArr(arr,Num)
|
|
{
|
|
var len = arr.length;
|
|
arr[len] = Num & 0xFF;
|
|
arr[len + 1] = (Num >>> 8) & 0xFF;
|
|
arr[len + 2] = (Num >>> 16) & 0xFF;
|
|
arr[len + 3] = (Num >>> 24) & 0xFF;
|
|
var NumH = Math.floor(Num / 4294967296);
|
|
arr[len + 4] = NumH & 0xFF;
|
|
arr[len + 5] = (NumH >>> 8) & 0xFF;
|
|
};
|
|
|
|
function WriteUintToArrOnPos(arr,Num,Pos)
|
|
{
|
|
arr[Pos] = Num & 0xFF;
|
|
arr[Pos + 1] = (Num >>> 8) & 0xFF;
|
|
arr[Pos + 2] = (Num >>> 16) & 0xFF;
|
|
arr[Pos + 3] = (Num >>> 24) & 0xFF;
|
|
var NumH = Math.floor(Num / 4294967296);
|
|
arr[Pos + 4] = NumH & 0xFF;
|
|
arr[Pos + 5] = (NumH >>> 8) & 0xFF;
|
|
};
|
|
|
|
function WriteUint32ToArr(arr,Num)
|
|
{
|
|
var len = arr.length;
|
|
arr[len] = Num & 0xFF;
|
|
arr[len + 1] = (Num >>> 8) & 0xFF;
|
|
arr[len + 2] = (Num >>> 16) & 0xFF;
|
|
arr[len + 3] = (Num >>> 24) & 0xFF;
|
|
};
|
|
|
|
function WriteUint32ToArrOnPos(arr,Num,Pos)
|
|
{
|
|
arr[Pos] = Num & 0xFF;
|
|
arr[Pos + 1] = (Num >>> 8) & 0xFF;
|
|
arr[Pos + 2] = (Num >>> 16) & 0xFF;
|
|
arr[Pos + 3] = (Num >>> 24) & 0xFF;
|
|
};
|
|
|
|
function WriteUint16ToArrOnPos(arr,Num,Pos)
|
|
{
|
|
arr[Pos] = Num & 0xFF;
|
|
arr[Pos + 1] = (Num >>> 8) & 0xFF;
|
|
};
|
|
|
|
function WriteArrToArr(arr,arr2,ConstLength)
|
|
{
|
|
var len = arr.length;
|
|
for(var i = 0; i < ConstLength; i++)
|
|
{
|
|
arr[len + i] = arr2[i];
|
|
}
|
|
};
|
|
|
|
function WriteArrToArrOnPos(arr,arr2,Pos,ConstLength)
|
|
{
|
|
for(var i = 0; i < ConstLength; i++)
|
|
{
|
|
arr[Pos + i] = arr2[i];
|
|
}
|
|
};
|
|
|
|
function WriteArrToArrHOnPos(arr,arr2,Pos,ConstLength)
|
|
{
|
|
for(var i = 0; i < ConstLength; i++)
|
|
{
|
|
arr[Pos + i] |= (arr2[i] << 8);
|
|
}
|
|
};
|
|
|
|
function ConvertBufferToStr(Data)
|
|
{
|
|
for(var key in Data)
|
|
{
|
|
var item = Data[key];
|
|
if(item instanceof Buffer)
|
|
{
|
|
Data[key] = GetHexFromArr(item);
|
|
}
|
|
else
|
|
if(typeof item === "object")
|
|
ConvertBufferToStr(item);
|
|
}
|
|
};
|
|
|
|
function CopyObjValue(obj,num)
|
|
{
|
|
if(num && num > 5)
|
|
return obj;
|
|
var ret = {};
|
|
for(var key in obj)
|
|
{
|
|
var val = obj[key];
|
|
if((typeof val === "object") && !(val instanceof Buffer) && !(val instanceof ArrayBuffer) && !(val instanceof Array))
|
|
val = CopyObjValue(val, num + 1);
|
|
ret[key] = val;
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
function CopyArr(arr1)
|
|
{
|
|
var arr2 = [];
|
|
if(arr1)
|
|
for(var i = 0; i < arr1.length; i++)
|
|
arr2[i] = arr1[i];
|
|
return arr2;
|
|
};
|
|
|
|
function ParseNum(a)
|
|
{
|
|
var Num = parseInt(a);
|
|
if(!Num)
|
|
Num = 0;
|
|
if(isNaN(Num))
|
|
Num = 0;
|
|
if(Num < 0)
|
|
Num = 0;
|
|
return Num;
|
|
};
|
|
|
|
function CompareArr(a,b)
|
|
{
|
|
for(var i = 0; i < a.length; i++)
|
|
{
|
|
if(a[i] !== b[i])
|
|
return a[i] - b[i];
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
function CompareArrL(a,b)
|
|
{
|
|
if(a.length !== b.length)
|
|
return a.length - b.length;
|
|
for(var i = 0; i < a.length; i++)
|
|
{
|
|
if(a[i] !== b[i])
|
|
return a[i] - b[i];
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
function GetSeqHash(BlockNum,PrevHash,TreeHash)
|
|
{
|
|
var arr = [GetArrFromValue(BlockNum), PrevHash, TreeHash];
|
|
var SeqHash = CalcHashFromArray(arr, true);
|
|
return SeqHash;
|
|
};
|
|
|
|
function arr2(Value1,Value2)
|
|
{
|
|
var Buf = [];
|
|
for(var n = 0; n < Value1.length; n++)
|
|
Buf.push(Value1[n]);
|
|
for(var n = 0; n < Value2.length; n++)
|
|
Buf.push(Value2[n]);
|
|
return Buf;
|
|
};
|
|
|
|
function shaarr2(Value1,Value2)
|
|
{
|
|
return shaarr(arr2(Value1, Value2));
|
|
};
|
|
|
|
function sha3arr2(Value1,Value2)
|
|
{
|
|
return sha3(arr2(Value1, Value2));
|
|
};
|
|
|
|
function GetBlockArrFromBuffer(BufRead,Info)
|
|
{
|
|
if(!BufRead || BufRead.length < 10)
|
|
return [];
|
|
var BLOCK_PROCESSING_LENGTH = 8;
|
|
var BLOCK_PROCESSING_LENGTH2 = BLOCK_PROCESSING_LENGTH * 2;
|
|
BufRead.len = 0;
|
|
var StartNum = ReadUintFromArr(BufRead);
|
|
var CountLoad = ReadUint32FromArr(BufRead);
|
|
var BufSize = 6 + 4 + BLOCK_PROCESSING_LENGTH2 * 32 + 32 + 6 + CountLoad * 64;
|
|
if(CountLoad <= 0 || BufSize !== BufRead.length)
|
|
{
|
|
return [];
|
|
}
|
|
var PrevBlock;
|
|
var BlockArr = [];
|
|
for(var i = 0; i < CountLoad + BLOCK_PROCESSING_LENGTH2; i++)
|
|
{
|
|
var Block = {};
|
|
Block.BlockNum = StartNum + i;
|
|
if(i < BLOCK_PROCESSING_LENGTH2)
|
|
{
|
|
Block.Hash = ReadArrFromArr(BufRead, 32);
|
|
}
|
|
else
|
|
{
|
|
if(i === BLOCK_PROCESSING_LENGTH2)
|
|
{
|
|
Block.SumHash = ReadArrFromArr(BufRead, 32);
|
|
Block.SumPow = ReadUintFromArr(BufRead);
|
|
}
|
|
Block.TreeHash = ReadArrFromArr(BufRead, 32);
|
|
Block.AddrHash = ReadArrFromArr(BufRead, 32);
|
|
var arr = [];
|
|
var start = i - BLOCK_PROCESSING_LENGTH2;
|
|
for(var n = 0; n < BLOCK_PROCESSING_LENGTH; n++)
|
|
{
|
|
var Prev = BlockArr[start + n];
|
|
arr.push(Prev.Hash);
|
|
}
|
|
Block.PrevHash = CalcHashFromArray(arr, true);
|
|
Block.SeqHash = GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash);
|
|
var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28);
|
|
var PrevAddrNum = ReadUint32FromArr(Block.AddrHash, 28);
|
|
if(PrevHashNum !== PrevAddrNum && Block.BlockNum > 20000000)
|
|
{
|
|
if(global.WATCHDOG_DEV)
|
|
{
|
|
var Str = "";
|
|
if(Info && Info.Node)
|
|
Str = " from " + NodeName(Info.Node);
|
|
ToError("Error on block load: " + Block.BlockNum + Str);
|
|
}
|
|
return [];
|
|
}
|
|
CalcHashBlockFromSeqAddr(Block, Block.PrevHash);
|
|
Block.Power = GetPowPower(Block.PowHash);
|
|
if(PrevBlock)
|
|
{
|
|
Block.SumHash = shaarr2(PrevBlock.SumHash, Block.Hash);
|
|
}
|
|
PrevBlock = Block;
|
|
}
|
|
Block.TrCount = 0;
|
|
Block.TrDataPos = 0;
|
|
Block.TrDataLen = 0;
|
|
BlockArr.push(Block);
|
|
}
|
|
for(var i = BlockArr.length - 1; i >= 0; i--)
|
|
{
|
|
var Block = BlockArr[i];
|
|
if(!Block.SumHash)
|
|
{
|
|
BlockArr = BlockArr.slice(i + 1);
|
|
break;
|
|
}
|
|
}
|
|
return BlockArr;
|
|
};
|
|
|
|
function shaarrblock2(Value1,Value2,BlockNum)
|
|
{
|
|
return shaarrblock(arr2(Value1, Value2), BlockNum);
|
|
};
|
|
if(typeof global === "object")
|
|
{
|
|
global.ReadUint32FromArr = ReadUint32FromArr;
|
|
global.ReadUintFromArr = ReadUintFromArr;
|
|
global.ReadUint16FromArr = ReadUint16FromArr;
|
|
global.WriteUintToArr = WriteUintToArr;
|
|
global.WriteUint32ToArr = WriteUint32ToArr;
|
|
global.WriteUint32ToArrOnPos = WriteUint32ToArrOnPos;
|
|
global.WriteUint16ToArrOnPos = WriteUint16ToArrOnPos;
|
|
global.WriteUintToArrOnPos = WriteUintToArrOnPos;
|
|
global.WriteArrToArr = WriteArrToArr;
|
|
global.WriteArrToArrOnPos = WriteArrToArrOnPos;
|
|
global.WriteArrToArrHOnPos = WriteArrToArrHOnPos;
|
|
global.ConvertBufferToStr = ConvertBufferToStr;
|
|
global.CopyObjValue = CopyObjValue;
|
|
global.CopyArr = CopyArr;
|
|
global.ParseNum = ParseNum;
|
|
global.CompareArr = CompareArr;
|
|
global.CompareArrL = CompareArrL;
|
|
global.shaarr2 = shaarr2;
|
|
global.sha3arr2 = sha3arr2;
|
|
global.arr2 = arr2;
|
|
global.GetBlockArrFromBuffer = GetBlockArrFromBuffer;
|
|
global.shaarrblock2 = shaarrblock2;
|
|
}
|
|
else
|
|
if(typeof window === "object")
|
|
{
|
|
global = window;
|
|
}
|