Exemplo n.º 1
0
        private List <Task <InteropBlock> > CreateTaskList(BigInteger batchCount, BigInteger[] blockIds = null)
        {
            List <Task <InteropBlock> > taskList = new List <Task <InteropBlock> >();

            if (blockIds == null)
            {
                var _interopBlockHeight = BigInteger.Parse(OracleReader.GetCurrentHeight("neo", "neo"));

                var nextCurrentBlockHeight = _interopBlockHeight + batchCount;

                for (var i = _interopBlockHeight; i < nextCurrentBlockHeight; i++)
                {
                    var url = DomainExtensions.GetOracleBlockURL(
                        "neo", "neo", PBigInteger.FromUnsignedArray(i.ToByteArray(), true));

                    taskList.Add(CreateTask(url));
                }
            }
            else
            {
                foreach (var blockId in blockIds)
                {
                    var url = DomainExtensions.GetOracleBlockURL(
                        "neo", "neo", PBigInteger.FromUnsignedArray(blockId.ToByteArray(), true));
                    taskList.Add(CreateTask(url));
                }
            }

            return(taskList);
        }
Exemplo n.º 2
0
        private InteropBlock GetInteropBlock(BigInteger blockId)
        {
            var url = DomainExtensions.GetOracleBlockURL(
                "neo", "neo", PBigInteger.FromUnsignedArray(blockId.ToByteArray(), true));

            return(OracleReader.Read <InteropBlock>(DateTime.Now, url));
        }
Exemplo n.º 3
0
        public static InteropTransaction MakeInteropTx(Logger logger, NeoTx tx, NeoAPI api, string[] origSwapAddresses,
                                                       string coldStorage)
        {
            logger.Debug("checking tx: " + tx.Hash);
            var swapAddresses = new List <Address>();

            foreach (var addr in origSwapAddresses)
            {
                swapAddresses.Add(NeoWallet.EncodeAddress(addr));
            }

            List <InteropTransfer> interopTransfers = new List <InteropTransfer>();

            var emptyTx = new InteropTransaction(Hash.Null, interopTransfers.ToArray());

            PBigInteger amount;
            var         witness = tx.witnesses.ElementAtOrDefault(0);

            if (witness == null)
            {
                // tx has no witness
                return(emptyTx);
            }

            var interopAddress = witness.ExtractAddress();

            if (tx.witnesses.Length != 1 || interopAddress == Address.Null || interopAddress == null)
            {
                //currently only one witness allowed
                // if ExtractAddress returns Address.Null, the tx is not properly signed
                return(emptyTx);
            }

            var sourceScriptHash = witness.verificationScript.Sha256().RIPEMD160();
            var sourceAddress    = NeoWallet.EncodeByteArray(sourceScriptHash);
            var sourceDecoded    = NeoWallet.DecodeAddress(sourceAddress);

            if (sourceAddress == interopAddress || sourceDecoded == coldStorage)
            {
                logger.Warning("self send tx or cold storage transfer found, ignoring: " + tx.Hash);
                // self send, probably consolidation tx, ignore
                return(emptyTx);
            }

            //logger.Debug("interop address: " + interopAddress);
            //logger.Debug("xswapAddress: " + swapAddress);
            //logger.Debug("interop sourceAddress: " + sourceAddress);
            //logger.Debug("neo sourceAddress: " + NeoWallet.DecodeAddress(sourceAddress));

            if (tx.attributes != null && tx.attributes.Length > 0)
            {
                foreach (var attr in tx.attributes)
                {
                    if (attr.Usage == TransactionAttributeUsage.Description)
                    {
                        try
                        {
                            var text = Encoding.UTF8.GetString(attr.Data);
                            if (Address.IsValidAddress(text))
                            {
                                interopAddress = Address.FromText(text);
                                //logger.Debug("new interop address: " + interopAddress);
                            }
                        }
                        catch {}
                    }
                }
            }

            if (tx.outputs.Length > 0)
            {
                foreach (var output in tx.outputs)
                {
                    var targetAddress = NeoWallet.EncodeByteArray(output.scriptHash.ToArray());
                    //logger.Debug("interop targetAddress : " + targetAddress);
                    //logger.Debug("neo targetAddress: " + NeoWallet.DecodeAddress(targetAddress));
                    //logger.Debug("interopSwapAddress: " + interopSwapAddress);
                    //logger.Debug("targetAddress: " + targetAddress);

                    //var swpAddress = NeoWallet.EncodeAddress(swapAddress);
                    //logger.Debug("interop swpAddress: " + swpAddress);
                    //logger.Debug("neo swpAddress: " + NeoWallet.DecodeAddress(swpAddress));
                    //if (targetAddress.ToString() == swapAddress)
                    if (swapAddresses.Contains(targetAddress))
                    {
                        var token = FindSymbolFromAsset(new UInt256(output.assetID).ToString());
                        CryptoCurrencyInfo tokenInfo;
                        if (NeoTokenInfo.TryGetValue(token, out tokenInfo))
                        {
                            amount = Phantasma.Numerics.UnitConversion.ToBigInteger(
                                output.value, tokenInfo.Decimals);
                        }
                        else
                        {
                            // asset not swapable at the moment...
                            //logger.Debug("Asset not swapable");
                            return(emptyTx);
                        }

                        //logger.Debug("UTXO " + amount);
                        interopTransfers.Add
                        (
                            new InteropTransfer
                            (
                                NeoWallet.NeoPlatform,
                                sourceAddress,
                                DomainSettings.PlatformName,
                                targetAddress,
                                interopAddress, // interop address
                                token.ToString(),
                                amount
                            )
                        );
                    }
                }
            }

            if (tx.script != null && tx.script.Length > 0) // NEP5 transfers
            {
                var script = NeoDisassembler.Disassemble(tx.script, true);

                //logger.Debug("SCRIPT ====================");
                //foreach (var entry in script.lines)
                //{
                //    logger.Debug($"{entry.name} : { entry.opcode }");
                //}
                //logger.Debug("SCRIPT ====================");

                if (script.lines.Count() < 7)
                {
                    //logger.Debug("NO SCRIPT!!!!");
                    return(emptyTx);
                }

                var disasmEntry = script.lines.ElementAtOrDefault(6);

                //if ( disasmEntry == null )
                //{
                //    logger.Debug("disasmEntry is null");
                //}
                //if ( disasmEntry != null )
                //{
                //    if ( disasmEntry.data == null)
                //        logger.Debug("disasmEntry.data is 0");
                //}

                if (disasmEntry.name != "APPCALL" || disasmEntry.data == null || disasmEntry.data.Length == 0)
                {
                    //logger.Debug("NO APPCALL");
                    return(emptyTx);
                }
                else
                {
                    var assetString = new UInt160(disasmEntry.data).ToString();
                    if (string.IsNullOrEmpty(assetString) || FindSymbolFromAsset(assetString) == null)
                    {
                        //logger.Debug("Ignore TX due to non swapable token.");
                        return(emptyTx);
                    }
                }

                int pos = 0;
                foreach (var entry in script.lines)
                {
                    pos++;
                    if (pos > 3)
                    {
                        // we are only interested in the first three elements
                        break;
                    }

                    if (entry.data == null || entry.data.Length == 0)
                    {
                        logger.Debug("Ignore tx, invalid data field: " + tx);
                        return(emptyTx);
                    }

                    if (pos == 1)
                    {
                        amount = PBigInteger.FromUnsignedArray(entry.data, true);
                    }
                    if (pos == 2 || pos == 3)
                    {
                        if (pos == 2)
                        {
                            if (entry.data == null || entry.data.Length == 0)
                            {
                                logger.Debug("Invalid op on pos 2, ignoring tx: " + tx);
                                return(emptyTx);
                            }
                            var targetScriptHash = new UInt160(entry.data);
                            //logger.Debug("neo targetAddress: " + targetScriptHash.ToAddress());
                            var targetAddress = NeoWallet.EncodeByteArray(entry.data);
                            //logger.Debug("targetAddress : " + targetAddress);
                            //logger.Debug("interopSwapAddress: " + interopSwapAddress);
                            //logger.Debug("SwapAddress: " + swapAddress);
                            if (swapAddresses.Contains(targetAddress))
                            {
                                // found a swap, call getapplicationlog now to get transaction details and verify the tx was actually processed.
                                ApplicationLog[] appLogs = null;
                                try
                                {
                                    appLogs = api.GetApplicationLog(tx.Hash);
                                }
                                catch (Exception e)
                                {
                                    logger.Error("Getting application logs failed: " + e.Message);
                                    return(new InteropTransaction(Hash.Null, interopTransfers.ToArray()));
                                }

                                if (appLogs != null)
                                {
                                    for (var i = 0; i < appLogs.Length; i++)
                                    {
                                        //logger.Debug("appLogs[i].contract" + appLogs[i].contract);
                                        var token = FindSymbolFromAsset(appLogs[i].contract);
                                        //logger.Debug("TOKEN::::::::::::::::::: " + token);
                                        //logger.Debug("amount: " + appLogs[i].amount + " " + token);
                                        var sadd = NeoWallet.EncodeByteArray(appLogs[i].sourceAddress.ToArray());
                                        var tadd = NeoWallet.EncodeByteArray(appLogs[i].targetAddress.ToArray());


                                        interopTransfers.Add
                                        (
                                            new InteropTransfer
                                            (
                                                "neo", // todo Pay.Chains.NeoWallet.NeoPlatform
                                                       //NeoWallet.EncodeByteArray(appLogs[i].sourceAddress.ToArray()),
                                                sourceAddress,
                                                DomainSettings.PlatformName,
                                                targetAddress,
                                                interopAddress, // interop address
                                                token,
                                                appLogs[i].amount
                                            )
                                        );
                                    }
                                }
                                else
                                {
                                    logger.Warning("Neo swap is found but application log is not available for tx " + tx.Hash);
                                }
                            }
                        }
                        else
                        {
                            //TODO reverse swap
                            sourceScriptHash = new UInt160(entry.data).ToArray();
                            sourceAddress    = NeoWallet.EncodeByteArray(sourceScriptHash.ToArray());
                        }
                    }
                }
            }

            var total = interopTransfers.Count();

            if (total > 0)
            {
                logger.Message($"Found {total} swaps in neo tx {tx.Hash}");
            }
            else
            {
                logger.Debug($"No swaps in neo tx {tx.Hash}");
            }

            return((interopTransfers.Count() > 0)
                ? new InteropTransaction(Hash.Parse(tx.Hash.ToString()), interopTransfers.ToArray())
                : new InteropTransaction(Hash.Null, interopTransfers.ToArray()));
        }
Exemplo n.º 4
0
        public override ApplicationLog[] GetApplicationLog(UInt256 hash)
        {
            if (!HasPlugin("ApplicationLogs"))
            {
                return(null);
            }

            var response = QueryRPC("getapplicationlog", new object[] { hash.ToString() });

            if (response != null && response.HasNode("result"))
            {
                //var json = LunarLabs.Parser.JSON.JSONReader.ReadFromString(response);
                List <ApplicationLog> appLogList = new List <ApplicationLog>();

                var executions = response["result"]["executions"];
                //LogData(executions);
                for (var i = 0; i < executions.ChildCount; i++)
                {
                    VMState vmstate;
                    if (Enum.TryParse(executions[i].GetString("vmstate"), out vmstate))
                    {
                        //LogData(executions[i]["notifications"][0]["state"]["value"]);
                        var notifications = executions[i]["notifications"];
                        for (var j = 0; j < notifications.ChildCount; j++)
                        {
                            var         states   = notifications[j]["state"]["value"];
                            string      txevent  = "";
                            UInt160     source   = UInt160.Zero;
                            UInt160     target   = UInt160.Zero;
                            PBigInteger amount   = 0;
                            var         contract = notifications[j].GetString("contract");

                            if (states[0].GetString("type") == "ByteArray")
                            {
                                txevent = (states[0].GetString("value"));
                            }

                            if (states[1].GetString("type") == "ByteArray" &&
                                !string.IsNullOrEmpty(states[1].GetString("value")))
                            {
                                source = UInt160.Parse(states[1].GetString("value"));
                            }

                            if (states[2].GetString("type") == "ByteArray" &&
                                !string.IsNullOrEmpty(states[2].GetString("value")))
                            {
                                target = UInt160.Parse(states[2].GetString("value"));
                            }

                            if (states[3].GetString("type") == "ByteArray")
                            {
                                amount = PBigInteger.FromUnsignedArray(states[3].GetString("value").HexToBytes(), true); // needs to be Phantasma.Numerics.BigInteger for now.
                            }
                            appLogList.Add(new ApplicationLog(vmstate, contract, txevent, source, target, amount));
                        }
                    }
                }

                return(appLogList.ToArray());
            }
            else
            {
                return(null);
            }
        }
Exemplo n.º 5
0
        public override IEnumerable <PendingSwap> Update()
        {
            // wait another 10s to execute eth interop
            //Task.Delay(10000).Wait();
            try
            {
                lock (String.Intern("PendingSetCurrentHeight_" + BSCWallet.BSCPlatform))
                {
                    var result = new List <PendingSwap>();

                    // initial start, we have to verify all processed swaps
                    if (initialStart)
                    {
                        Logger.Debug($"Read all bsc blocks now.");
                        var allInteropBlocks = OracleReader.ReadAllBlocks(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform);

                        Logger.Debug($"Found {allInteropBlocks.Count} blocks");

                        foreach (var block in allInteropBlocks)
                        {
                            ProcessBlock(block, ref result);
                        }

                        initialStart = false;

                        // return after the initial start to be able to process all swaps that happend in the mean time.
                        return(result);
                    }

                    var currentHeight       = ethAPI.GetBlockHeight();
                    var _interopBlockHeight = BigInteger.Parse(OracleReader.GetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform));
                    Logger.Debug($"Swaps: Current Eth chain height: {currentHeight}, interop: {_interopBlockHeight}, delta: {currentHeight - _interopBlockHeight}");

                    var blocksProcessedInOneBatch = 0;
                    while (blocksProcessedInOneBatch < 50)
                    {
                        if (_resyncBlockIds.Any())
                        {
                            for (var i = 0; i < _resyncBlockIds.Count; i++)
                            {
                                var blockId = _resyncBlockIds.ElementAt(i);
                                if (blockId > _interopBlockHeight)
                                {
                                    this.Logger.Warning($"EthInterop:Update() resync block {blockId} higher than current interop height, can't resync.");
                                    _resyncBlockIds.RemoveAt(i);
                                    continue;
                                }

                                try
                                {
                                    this.Logger.Debug($"EthInterop:Update() resync block {blockId} now.");
                                    var block = GetInteropBlock(blockId);
                                    ProcessBlock(block, ref result);
                                }
                                catch (Exception e)
                                {
                                    this.Logger.Error($"EthInterop:Update() resync block {blockId} failed: " + e);
                                }
                                _resyncBlockIds.RemoveAt(i);
                            }
                        }

                        blocksProcessedInOneBatch++;

                        var blockDifference = currentHeight - _interopBlockHeight;
                        if (blockDifference < confirmations)
                        {
                            // no need to query the node yet
                            break;
                        }

                        //TODO quick sync not done yet, requieres a change to the oracle impl to fetch multiple blocks
                        //var nextHeight = (blockDifference > 50) ? 50 : blockDifference; //TODO

                        //var transfers = new Dictionary<string, Dictionary<string, List<InteropTransfer>>>();

                        //if (nextHeight > 1)
                        //{
                        //    var blockCrawler = new EthBlockCrawler(logger, contracts.ToArray(), 0/*confirmations*/, ethAPI); //TODO settings confirmations

                        //    blockCrawler.Fetch(currentHeight, nextHeight);
                        //    transfers = blockCrawler.ExtractInteropTransfers(logger, LocalAddress);
                        //    foreach (var entry in transfers)
                        //    {
                        //        foreach (var txInteropTransfer in entry.Value)
                        //        {
                        //            foreach (var interopTransfer in txInteropTransfer.Value)
                        //            {
                        //                result.Add(new PendingSwap(
                        //                    this.PlatformName
                        //                    ,Hash.Parse(entry.Key)
                        //                    ,interopTransfer.sourceAddress
                        //                    ,interopTransfer.interopAddress)
                        //                );
                        //            }
                        //        }
                        //    }

                        //    _interopBlockHeight = nextHeight;
                        //    oracleReader.SetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, _interopBlockHeight.ToString());
                        //}
                        //else
                        //{

                        /* Future improvement, implement oracle call to fetch multiple blocks */
                        var url = DomainExtensions.GetOracleBlockURL(
                            BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, PBigInteger.FromUnsignedArray(_interopBlockHeight.ToByteArray(), true));

                        var interopBlock = OracleReader.Read <InteropBlock>(DateTime.Now, url);

                        ProcessBlock(interopBlock, ref result);

                        _interopBlockHeight++;
                        //}
                    }

                    OracleReader.SetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, _interopBlockHeight.ToString());

                    var total = result.Count();
                    if (total > 0)
                    {
                        Logger.Message($"startup: found {total} bsc swaps");
                    }
                    else
                    {
                        Logger.Debug($"did not find any bsc swaps");
                    }
                    return(result);
                }
            }
            catch (Exception e)
            {
                var logMessage = "BSCInterop.Update() exception caught:\n" + e.Message;
                var inner      = e.InnerException;
                while (inner != null)
                {
                    logMessage += "\n---> " + inner.Message + "\n\n" + inner.StackTrace;
                    inner       = inner.InnerException;
                }
                logMessage += "\n\n" + e.StackTrace;

                Logger.Error(logMessage);

                return(new List <PendingSwap>());
            }
        }