/// <summary> /// 交易业务说明 /// SendRaw是将交易数据从 任意节点(任意节点包括共识节点) 流转到 一个共识节点的过程 /// /// 1.流转说明 /// 如果SendRaw发起者就是共识节点,则不需要再流转了,直接处理交易 /// 如果不是,只流转给自己连接的节点中plevel 小于等于自己的,这个没见到 /// 2.sendraw参数 /// SendRaw(byte[] message,SignData) /// 发送交易只需要两个数据,一个 bytearray,一个signdata,一定是byte[],不要整什么MessagePackObjectList /// signdata参考neo的最简形态,我们只支持最简的 txpool.TransactionSign 写在那里的 /// 3.流转验证 /// 每一次流转,都要检查sendraw 数据对不对 /// signdata里面的vscript 包含公钥,iscript包含签名数据,执行ecc验签,不通过不转发,还记录本地黑名单,第二次收到,都不需要验证 /// /// 4.txid /// 交易的id ,就是交易message 的 hash256,保持和neo兼容 /// /// 5.共识节点收到交易的处理 /// 交易不是块,和块没有关系 /// 先忽略共识过程,系统就一个共识节点,自己就是议长。议长干的第一件事是构造一个统一的交易内存池 /// 收到交易,只需要存在内存里 /// 我们先假设所有共识节点有同样的交易index,交易的index是由议长分配的,议长分配完id,告知所有的共识节点 /// /// 当前共识节点收到交易,给他分配一个index,就存在自己的内存池里,不需要存数据库。 /// 分配了index的交易就可以全网广播,>=plevel /// 然后开一个定时器,定时从自己的内存池里挑一些交易,组装成块,广播 /// /// block 的header 包括当前块所包含的交易的hash /// block 的body 就是 所有的包含的交易的 message 和 signdata /// 只需要广播block的header,block的body 各个节点自己就可以组装 /// /// 6.错过广播 /// 错过广播是很正常的,所以每个节点有一个高度设计,就是block的index /// 可以找任意高度大于自己的节点索要指定的block header(by block index or block id) 和 指定的hash(by txid) /// /// 7.数据存储 /// 对共识节点,仅当组装成块的时候,一次性写入 block header、block涉及的交易、当前高度,用db 的 writebatch 方式 /// 刚收到的交易不写数据库,仅有随块一起写入的,并且已写入的交易,内存池里就不必保持了。 /// 但是所有的txid->block index 的映射,内存池里要保持 /// </summary> /// <param name="from"></param> /// <param name="dict"></param> //static DateTime start; //static int recvcount = 0; void OnRecv_Post_SendRaw(IModulePipeline from, MessagePackObjectDictionary dict) { //if(recvcount == 0 ) //{ // start = DateTime.Now; //} //recvcount++; logger.Info($"------OnRecv_Post_SendRaw From:{from?.system?.Remote?.ToString()??"Local"} -------"); //验证交易合法性,合法就收 var signData = SerializeHelper.DeserializeWithBinary <TransactionSign>(dict["signData"].AsBinary()); bool sign = Helper_NEO.VerifySignature(dict["message"].AsBinary(), signData.IScript, signData.VScript); if (!sign) { logger.Info($"------OnRecv_Post_SendRaw sign error -------"); return; } //if (recvcount % 20 == 0) //{ // var end = DateTime.Now; // logger.Info("recv count:" + recvcount + " span=" + (end - start).TotalMilliseconds + " txpool.discard"+ TXPool.txpoolcount); //} //收到消息后要么转发,要么保存 if (this.isProved) { Transaction trans = new Transaction(); trans.Index = this.txpool.MaxTransactionID; trans.message = dict["message"].AsBinary(); trans.signdata = signData; lock (blockTimerLock) { this.txpool.AddTx(trans); } //向内存池保存完,向全网广播这个交易 foreach (var item in this.linkNodes) { if (item.Value.hadJoin) { Tell_BoardCast_Tx(item.Value.remoteNode, dict["message"].AsBinary(), dict["signData"].AsBinary()); } } } else { //只流转给非记账节点,按照优先级,小于等于自己的其中一个 LinkObj minLink = null; foreach (var item in this.linkNodes) { if ((minLink == null || item.Value.pLevel < minLink.pLevel) && (item.Value.hadJoin)) { minLink = item.Value; } } if (minLink != null) { Tell_SendRaw(minLink.remoteNode, dict["message"].AsBinary(), dict["signData"].AsBinary()); } } }
/// <summary> /// 根据data得到挑选 dataserver /// </summary> /// <param name="data"></param> /// <returns></returns> IModulePipeline getServer(byte[] data) { int hash = Helper_NEO.CalcHash256(data).GetHashCode() % serverPath.Count; var path = serverPath[hash]; return(this.DataServerDic[path]); }
public byte[] GetPrivate(ThinNeo.NEP6.ScryptParameters sp, string password) { if (nep2key == null) { return(null); } return(Helper_NEO.GetPrivateKeyFromNEP2(nep2key, password, sp.N, sp.R, sp.P)); }
public Module_Node(AllPet.Common.ILogger logger, Newtonsoft.Json.Linq.JObject configJson) : base(true) { this.guid = Helper_NEO.CalcHash256(Guid.NewGuid().ToByteArray()); this.logger = logger; this.config = new Config_Module(configJson); this.chainHash = Helper_NEO.CalcHash256(this.config.ChainInfo.ToInitScript()); //this.config = new Config_ChainInit(configJson); this.linkNodes = new System.Collections.Concurrent.ConcurrentDictionary <ulong, LinkObj>(); this.provedNodes = new System.Collections.Concurrent.ConcurrentDictionary <ulong, LinkObj>(); this.linkIDs = new System.Collections.Concurrent.ConcurrentDictionary <string, ulong>(); this.listCanlink = new Struct.ThreadSafeQueueWithKey <CanLinkObj>(); try { if (configJson.ContainsKey("Key_Nep2") && configJson.ContainsKey("Key_Password")) { var nep2 = configJson["Key_Nep2"].AsString(); var password = configJson["Key_Password"].AsString(); this.prikey = Helper_NEO.GetPrivateKeyFromNEP2(nep2, password); this.pubkey = Helper_NEO.GetPublicKey_FromPrivateKey(prikey); //区分记账人 var address = Helper_NEO.GetAddress_FromPublicKey(pubkey); //证明人的地址 //如果证明人的地址和初始记账人的地址相同即为记账人 if (this.config.ChainInfo.InitOwner.Contains(address)) { this.isProved = true; this.pLevel = 0;//记账节点 } } //return; blockChain = new BlockChain(); blockChain.InitChain(this.config.SimpleDbPath, this.config.ChainInfo); this.blockIndex = blockChain.GetBlockCount(); //记账节点才需要出块 if (this.isProved) { this.blockTimer = new System.Timers.Timer(); this.blockTimer.Interval = blockTime * 1000; //毫秒 this.blockTimer.Enabled = true; this.blockTimer.AutoReset = true; //一直执行true this.blockTimer.Elapsed += new System.Timers.ElapsedEventHandler(MakeBlock); this.blockTimer.Start(); } } catch (Exception err) { logger.Error("Error in Get Prikey:" + err.ToString()); throw new Exception("error in get prikey.", err); } this.txpool = new Node.TXPool(); ResetCanlinkList(); }
public bool VerifyPassword(string password) { try { var prikey = Helper_NEO.GetPrivateKeyFromNEP2(nep2key, password); return(true); } catch (FormatException) { return(false); } }
void OnRecv_Response_Tx(IModulePipeline from, MessagePackObjectDictionary dict) { var tx = dict["tx"].AsBinary(); if (tx != null) { var trans = SerializeHelper.DeserializeWithBinary <Transaction>(tx); //验证交易合法性,合法就收 bool sign = Helper_NEO.VerifySignature(trans.message, trans.signdata.IScript, trans.signdata.VScript); if (!sign) { return; } this.txpool.AddTx(trans); } }
void OnRecv_BoardCast_Tx(IModulePipeline from, MessagePackObjectDictionary dict) { var signData = SerializeHelper.DeserializeWithBinary <TransactionSign>(dict["signData"].AsBinary()); bool sign = Helper_NEO.VerifySignature(dict["message"].AsBinary(), signData.IScript, signData.VScript); if (!sign) { return; } Transaction trans = new Transaction(); trans.Index = this.txpool.MaxTransactionID; trans.message = dict["message"].AsBinary(); trans.signdata = signData; this.txpool.AddTx(trans); }
public JObject ToJson() { JObject account = new JObject(); byte[] shash = (ScriptHash); var addr = Helper_NEO.GetAddress_FromScriptHash(shash); account["address"] = addr; account["label"] = null; account["isDefault"] = false; account["lock"] = false; account["key"] = nep2key; account["contract"] = ((NEP6Contract)Contract)?.ToJson(); account["extra"] = null; return(account); }
public void AddTx(Transaction trans) { //第一步,验证交易合法性,合法就收 //第二步,验证Hash是否已经存在 var txid = Helper_NEO.CalcHash256(trans.message); if (TXData.ContainsKey(txid)) { //txpoolcount++; return; } //第三步,放进去并调整MaxTransactionID TXData.TryAdd(txid, trans); map_tx2index.TryAdd(MaxTransactionID, txid); MaxTransactionID++; }
public RPC_Result RPC_SendRawTransaction(IList <MessagePackObject> _params) { var message = _params.First(); var pubkey = this.pubkey; var sign = Helper_NEO.Sign(message.AsBinary(), this.prikey); var signdata = new TransactionSign(); signdata.VScript = pubkey; signdata.IScript = sign; var data = SerializeHelper.SerializeToBinary(signdata); this.Tell_SendRaw(this._System.GetPipeline(this, "this/node"), message.AsBinary(), data); var result = new MessagePackObject(0); return(new RPC_Result(result)); }
public static NEP6Account FromJson(Newtonsoft.Json.Linq.JObject json, NEP6Wallet wallet) { var strAdd = (json["address"] as Newtonsoft.Json.Linq.JValue).Value as string; var pubkeyhash = Helper_NEO.GetScriptHash_FromAddress(strAdd); string key = null; if (json.ContainsKey("key") && json["key"] != null) { key = json["key"].Value <string>(); } var acc = new NEP6Account(pubkeyhash, key); if (json.ContainsKey("contract") && json["contract"] != null) { acc.Contract = NEP6Contract.FromJson(json["contract"] as JObject); } return(acc); }
void OnRecv_ResponseAcceptJoin(IModulePipeline from, MessagePackObjectDictionary dict) { logger.Info("had join chain"); var link = this.linkNodes[from.system.PeerID]; link.hadJoin = true;//已经和某个节点接通 //如果连上了,标识连上的节点的优先级 var plevel = dict["plevel"].AsInt32(); this.getPlevelFromLinkObj(link, plevel); //Console.WriteLine("@ from:" + link.publicEndPoint + " plevel:" + link.pLevel + " node:" + this.config.PublicEndPoint + " plevel:" + this.pLevel); if (this.prikey != null)//有私钥证明一下 { var check = dict["checkinfo"].AsBinary(); var addinfo = Guid.NewGuid().ToByteArray(); var message = addinfo.Concat(check).ToArray(); var signdata = Helper_NEO.Sign(message, this.prikey); Tell_Request_ProvePeer(from, addinfo, signdata); } Tell_Request_PeerList(from); //如果连接上了,要更新自己的优先级 //if (this.pLevel < 0) //{ // if (link.pLevel >= 0)//加入的节点优先级有效,且本身节点不是记账人 // { // this.pLevel = link.pLevel + 1; // } //} //else if(this.pLevel > link.pLevel) //{ // this.pLevel = link.pLevel + 1; // //如果是变更,则广播低优先级节点 // foreach (var item in this.linkNodes) // { // if (item.Value.hadJoin && item.Value.pLevel < this.pLevel) // { // Tell_BoradCast_PeerState(item.Value.remoteNode); // } // } //} //System.Console.WriteLine($"node:{this.config.PublicEndPoint} pLeve:{this.pLevel} isProved:{this.isProved}"); }
void OnRecv_RequestProvePeer(IModulePipeline from, MessagePackObjectDictionary dict) { var link = this.linkNodes[from.system.PeerID]; var addinfo = dict["addinfo"].AsBinary(); var pubkey = dict["pubkey"].AsBinary(); var signdata = dict["signdata"].AsBinary(); var message = addinfo.Concat(link.CheckInfo).ToArray(); bool sign = Helper_NEO.VerifySignature(message, signdata, pubkey); if (sign) { link.PublicKey = pubkey; logger.Info("had a proved peer:" + Helper.Bytes2HexString(pubkey)); } else { logger.Info("had a error proved peer:" + Helper.Bytes2HexString(pubkey)); } }
public NEP6Account CreateAccount(byte[] privateKey, string password) { var pubkey = Helper_NEO.GetPublicKey_FromPrivateKey(privateKey); NEP6Contract contract = new NEP6Contract { Script = Helper_NEO.GetAddressScript_FromPublicKey(pubkey) }; var scripthash = Helper_NEO.CalcHash160(pubkey); var nep2key = Helper_NEO.GetNep2FromPrivateKey(privateKey, password); NEP6Account account = new NEP6Account(scripthash, nep2key) { Contract = contract }; AddAccount(account); return(account); }
private void Button_Click(object sender, RoutedEventArgs e) { Button btn = sender as Button; btn.IsEnabled = false; var address = AddressTextBox.Text; var startTime = StartTimeDatePicker.SelectedDate; try { Helper_NEO.GetScriptHash_FromAddress(address); } catch (Exception) { MessageBox.Show("Address Error"); return; } finally { btn.IsEnabled = true; } StateTextBlock.Text = $"Starting…"; DoEvents(); var totalEntries = 0; using (var web = new WebClient()) { var json = web.DownloadJson(address, 1); var totalPages = (int)json["total_pages"]; totalEntries = (int)json["total_entries"]; var pageSize = (int)json["page_size"]; txList.Clear(); var stop = false; for (int i = 1; i <= totalPages; i++) { json = web.DownloadJson(address, i); foreach (var item in json["entries"]) { var tx = Transaction.FromJson(item); if (tx != null) { if (startTime != null && tx.Time < startTime) { stop = true; break; } txList.Add(tx); } } if (stop) { break; } if (startTime == null) { StateTextBlock.Text = $"{Math.Min(i * pageSize, totalEntries)}/{totalEntries}"; } else { StateTextBlock.Text = $"{Math.Min(i * pageSize, totalEntries)}"; } DoEvents(); } } StateTextBlock.Text = $"Calculating…"; DoEvents(); ProcessData(); StateTextBlock.Text = $"Completed."; btn.IsEnabled = true; }