public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Logger logger, NeoBlock block, NeoAPI api, string[] swapAddresses, string coldStorage) { List <Hash> hashes = new List <Hash>(); //logger.Debug($"Read block {block.Height} with hash {block.Hash}"); // if the block has no swap tx, it's currently not of interest bool blockOfInterest = false; List <InteropTransaction> interopTransactions = new List <InteropTransaction>(); foreach (var tx in block.transactions) { if (tx.type == TransactionType.InvocationTransaction || tx.type == TransactionType.ContractTransaction) { var interopTx = MakeInteropTx(logger, tx, api, swapAddresses, coldStorage); if (interopTx.Hash != Hash.Null) { interopTransactions.Add(interopTx); hashes.Add(Hash.FromBytes(tx.Hash.ToArray())); blockOfInterest = true; } } } InteropBlock iBlock = (blockOfInterest) ? new InteropBlock("neo", "neo", Hash.Parse(block.Hash.ToString()), hashes.ToArray()) : new InteropBlock("neo", "neo", Hash.Null, hashes.ToArray()); return(Tuple.Create(iBlock, interopTransactions.ToArray())); }
public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Nexus nexus, Logger logger, EthAPI api , BigInteger height, string[] contracts, uint confirmations, string[] swapAddress) { Hash blockHash = Hash.Null; var interopTransactions = new List <InteropTransaction>(); //TODO HACK var combinedAddresses = contracts.ToList(); combinedAddresses.AddRange(swapAddress); Dictionary <string, Dictionary <string, List <InteropTransfer> > > transfers = new Dictionary <string, Dictionary <string, List <InteropTransfer> > >(); try { // TODO pass from outside to not instantiate for each call to MakeInteropBlock Func <string, Address> addressEncoder = (address) => { return(BSCWallet.EncodeAddress(address)); }; Func <Nethereum.RPC.Eth.DTOs.Transaction, Address> addressExtractor = (tx) => { return(BSCInterop.ExtractInteropAddress(tx)); }; var crawler = new EvmBlockCrawler(logger, combinedAddresses.ToArray(), confirmations, api, addressEncoder, addressExtractor, BSCWallet.BSCPlatform); // fetch blocks crawler.Fetch(height); transfers = crawler.ExtractInteropTransfers(nexus, logger, swapAddress); } catch (Exception e) { logger.Error("Failed to fetch eth blocks: " + e); } if (transfers.Count == 0) { var emptyBlock = new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, Hash.Null, new Hash[] {}); return(Tuple.Create(emptyBlock, interopTransactions.ToArray())); } blockHash = Hash.Parse(transfers.FirstOrDefault().Key); foreach (var block in transfers) { var txTransferDict = block.Value; foreach (var tx in txTransferDict) { var interopTx = MakeInteropTx(logger, tx.Key, tx.Value); if (interopTx.Hash != Hash.Null) { interopTransactions.Add(interopTx); } } } var hashes = interopTransactions.Select(x => x.Hash).ToArray(); InteropBlock interopBlock = (interopTransactions.Count() > 0) ? new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, blockHash, hashes) : new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, Hash.Null, hashes); return(Tuple.Create(interopBlock, interopTransactions.ToArray())); }
public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Nexus nexus, Logger logger, EthAPI api , BigInteger height, string[] contracts, uint confirmations, string swapAddress) { Hash blockHash = Hash.Null; var interopTransactions = new List <InteropTransaction>(); //TODO HACK var combinedAddresses = contracts.ToList(); combinedAddresses.Add(swapAddress); Dictionary <string, Dictionary <string, List <InteropTransfer> > > transfers = new Dictionary <string, Dictionary <string, List <InteropTransfer> > >(); try { var crawler = new EthBlockCrawler(logger, combinedAddresses.ToArray(), confirmations, api); // fetch blocks crawler.Fetch(height); transfers = crawler.ExtractInteropTransfers(nexus, logger, swapAddress); } catch (Exception e) { logger.Error("Failed to fetch eth blocks: " + e); } if (transfers.Count == 0) { var emptyBlock = new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, Hash.Null, new Hash[] {}); return(Tuple.Create(emptyBlock, interopTransactions.ToArray())); } blockHash = Hash.Parse(transfers.FirstOrDefault().Key); foreach (var block in transfers) { var txTransferDict = block.Value; foreach (var tx in txTransferDict) { var interopTx = MakeInteropTx(logger, tx.Key, tx.Value); if (interopTx.Hash != Hash.Null) { interopTransactions.Add(interopTx); } } } var hashes = interopTransactions.Select(x => x.Hash).ToArray(); InteropBlock interopBlock = (interopTransactions.Count() > 0) ? new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, blockHash, hashes) : new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, Hash.Null, hashes); return(Tuple.Create(interopBlock, interopTransactions.ToArray())); }
private void ProcessBlock(InteropBlock block, ref List <PendingSwap> result) { foreach (var txHash in block.Transactions) { var interopTx = OracleReader.ReadTransaction(BSCWallet.BSCPlatform, "bsc", txHash); foreach (var interopTransfer in interopTx.Transfers) { result.Add( new PendingSwap( this.PlatformName , txHash , interopTransfer.sourceAddress , interopTransfer.interopAddress) ); } } }
protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height) { InteropBlock interopBlock = null; switch (platformName) { case "neo": { switch (chainName) { // we abuse chainName here to simulate different results case "neoEmpty": interopBlock = new InteropBlock(platformName, chainName, Hash.Null, new Hash[0]); break; case "neo": interopBlock = new InteropBlock(platformName, chainName, Hash.FromString("neohash"), new Hash[0]); break; } } break; case "ethereum": { switch (chainName) { // we abuse chainName here to simulate different results case "ethereumEmpty": interopBlock = new InteropBlock(platformName, chainName, Hash.Null, new Hash[0]); break; case "ethereum": interopBlock = new InteropBlock(platformName, chainName, Hash.FromString("neohash"), new Hash[0]); break; } } break; } return(interopBlock); }
public InteropBlock ReadBlock(Hash hash) { var blockText = hash.ToString(); if (blockText.StartsWith("0x")) { blockText = blockText.Substring(2); } var apiCall = $"get_block/{blockText}"; var json = ExecuteRequest(apiCall); if (json == null) { throw new OracleException("Network read failure: " + apiCall); } try { var root = JSONReader.ReadFromString(json); var transactions = root.GetNode("transactions"); var hashes = new List <Hash>(); foreach (var entry in transactions.Children) { var txHash = Hash.Parse(entry.Value); hashes.Add(txHash); } var block = new InteropBlock(platformName, "main", Hash.Parse(blockText), hashes.ToArray()); return(block); } catch (Exception e) { throw new OracleException(e.Message); } }
private void ProcessBlock(InteropBlock block, List <PendingSwap> result) { foreach (var txHash in block.Transactions) { var interopTx = OracleReader.ReadTransaction("neo", "neo", txHash); if (interopTx.Transfers.Length == 0) { continue; } if (interopTx.Transfers.Length == 0) { continue; } InteropTransfer transfer; if (interopTx.Transfers.Length != 1) { var sources = interopTx.Transfers.Select(x => x.sourceAddress).Distinct(); if (sources.Count() > 1) { throw new OracleException("neo transfers with multiple source addresses not supported yet"); } var dests = interopTx.Transfers.Select(x => x.destinationAddress).Distinct(); if (dests.Count() > 1) { throw new OracleException("neo transfers with multiple destination addresses not supported yet"); } var interops = interopTx.Transfers.Select(x => x.interopAddress).Distinct(); if (interops.Count() > 1) { throw new OracleException("neo transfers with multiple interop addresses not supported yet"); } var symbols = interopTx.Transfers.Select(x => x.Symbol).Distinct(); if (symbols.Count() > 1) { throw new OracleException("neo transfers with multiple tokens not supported yet"); } PBigInteger sum = 0; foreach (var temp in interopTx.Transfers) { sum += temp.Value; } var first = interopTx.Transfers.First(); if (first.Data != null && first.Data.Length > 0) { throw new OracleException("neo transfers with custom data are not supported yet"); } transfer = new InteropTransfer(first.sourceChain, first.sourceAddress, first.destinationChain, first.destinationAddress, first.interopAddress, first.Symbol, sum); } else { transfer = interopTx.Transfers.First(); } if (transfer.sourceAddress == transfer.destinationAddress) // ignore this tx, this is a utxo consolidation { continue; } result.Add( new PendingSwap( this.PlatformName , txHash , transfer.sourceAddress , transfer.interopAddress) ); } }
protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt()) { if (hash == null && height == null) { throw new OracleException($"Fetching block not possible without hash or height"); } InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block); if (height == null && block.Hash != null && block.Hash != Hash.Null) { return(block); } Tuple <InteropBlock, InteropTransaction[]> interopTuple; switch (platformName) { case NeoWallet.NeoPlatform: NeoBlock neoBlock; if (height == 0) { neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes())); } else { neoBlock = _cli.NeoAPI.GetBlock(height); } if (neoBlock == null) { throw new OracleException($"Neo block is null"); } var coldStorage = _cli.Settings.Oracle.SwapColdStorageNeo; interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Neo], coldStorage); break; case EthereumWallet.EthereumPlatform: { var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Ethereum]); break; } case BSCWallet.BSCPlatform: { var hashes = _cli.Nexus.GetPlatformTokenHashes(BSCWallet.BSCPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = BSCInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.BscAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.BSC]); break; } default: throw new OracleException("Uknown oracle platform: " + platformName); } if (interopTuple.Item1.Hash != Hash.Null) { var initialStore = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block, interopTuple.Item1); var transactions = interopTuple.Item2; if (!initialStore) { logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!"); } foreach (var tx in transactions) { var txInitialStore = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx); if (!txInitialStore) { logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!"); } } } return(interopTuple.Item1); }
protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt()) { if (hash == null && height == null) { throw new OracleException($"Fetching block not possible without hash or height"); } InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block); if (height == null && block.Hash != null && block.Hash != Hash.Null) { return(block); } Tuple <InteropBlock, InteropTransaction[]> interopTuple; switch (platformName) { case NeoWallet.NeoPlatform: NeoBlock neoBlock; if (height == 0) { neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes())); } else { neoBlock = _cli.NeoAPI.GetBlock(height); } if (neoBlock == null) { throw new OracleException($"Neo block is null"); } interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[platformName]); break; case EthereumWallet.EthereumPlatform: //BlockWithTransactions ethBlock; //if (height == 0) //{ // //TODO MakeInteropBlock for a full block not done yet // //ethBlock = _cli.EthAPI.GetBlock(hash.ToString()); // //interopTuple = EthereumInterop.MakeInteropBlock(logger, ethBlock, _cli.EthAPI, _cli.TokenSwapper.swapAddress); //} //else //{ //} var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[platformName]); break; default: throw new OracleException("Uknown oracle platform: " + platformName); } if (interopTuple.Item1.Hash != Hash.Null) { var persisted = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block, interopTuple.Item1); if (persisted) { var transactions = interopTuple.Item2; foreach (var tx in transactions) { var txPersisted = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx); } } else { logger.Error($"Persisting oracle block { interopTuple.Item1.Hash } on platform { platformName } failed!"); } } return(interopTuple.Item1); }