public Transaction GenerateSideChainSend(KeyPair source, string tokenSymbol, Chain sourceChain, Address targetAddress, Chain targetChain, BigInteger amount, BigInteger fee) { Throw.IfNull(source, nameof(source)); Throw.If(!Nexus.TokenExists(tokenSymbol), "Token does not exist: " + tokenSymbol); Throw.IfNull(sourceChain, nameof(sourceChain)); Throw.IfNull(targetChain, nameof(targetChain)); Throw.If(amount <= 0, "positive amount required"); if (source.Address == targetAddress && tokenSymbol == Nexus.FuelTokenSymbol) { Throw.If(fee != 0, "no fees for same address"); } else { Throw.If(fee <= 0, "fee required when target is different address or token not native"); } var sb = ScriptUtils. BeginScript(). AllowGas(source.Address, Address.Null, MinimumFee, 9999); if (targetAddress != source.Address) { sb.CallContract("token", "SendTokens", targetChain.Address, source.Address, source.Address, Nexus.FuelTokenSymbol, fee); } var script = sb.CallContract("token", "SendTokens", targetChain.Address, source.Address, targetAddress, tokenSymbol, amount). SpendGas(source.Address). EndScript(); var tx = MakeTransaction(source, ProofOfWork.None, sourceChain, script); _pendingEntries[sourceChain] = new SideChainPendingBlock() { sourceChain = sourceChain, destChain = targetChain, hash = null, tokenSymbol = tokenSymbol }; return(tx); }
public IEnumerable <Block> EndBlock(Mempool mempool = null) { if (!blockOpen) { throw new Exception("Simulator block not open"); } usedAddresses.Clear(); blockOpen = false; var blocks = new List <Block>(); if (txChainMap.Count > 0) { var chains = txChainMap.Values.Distinct(); foreach (var chain in chains) { var hashes = txChainMap.Where((p) => p.Value == chain).Select(x => x.Key); if (hashes.Any()) { var txs = new List <Transaction>(); foreach (var hash in hashes) { txs.Add(txHashMap[hash]); } BigInteger nextHeight = chain.LastBlock != null ? chain.LastBlock.Height + 1 : Chain.InitialHeight; var prevHash = chain.LastBlock != null ? chain.LastBlock.Hash : Hash.Null; var block = new Block(nextHeight, chain.Address, CurrentTime, hashes, prevHash); bool submitted; string reason = "unknown"; if (mempool != null) { submitted = true; foreach (var tx in txs) { try { mempool.Submit(tx); } catch (Exception e) { reason = e.Message; submitted = false; break; } } } else { try { chain.BakeBlock(ref block, ref txs, MinimumFee, blockValidator, CurrentTime); chain.AddBlock(block, txs, MinimumFee); submitted = true; } catch (Exception e) { reason = e.Message; submitted = false; } } if (submitted) { blocks.Add(block); CurrentTime += blockTimeSkip; // add the finished block hash to each pending side chain tx if (_pendingEntries.Count > 0) { foreach (var entry in _pendingEntries.Values) { if (entry.sourceChain != chain) { continue; } var pendingBlock = new SideChainPendingBlock() { sourceChain = entry.sourceChain, destChain = entry.destChain, hash = block.Hash, tokenSymbol = entry.tokenSymbol }; _pendingBlocks.Add(pendingBlock); Logger.Debug($"...Sending {entry.sourceChain.Name}=>{entry.destChain.Name}: {block.Hash}"); } } Logger.Message($"End block #{step} @ {chain.Name} chain: {block.Hash}"); } else { throw new ChainException($"add block @ {chain.Name} failed, reason: {reason}"); } } } _pendingEntries.Clear(); return(blocks); } return(Enumerable.Empty <Block>()); }