private T ReadChainOracle <T>(string platformName, string chainName, string[] input) where T : class { if (input == null || input.Length != 2) { throw new OracleException("missing oracle input"); } var cmd = input[0].ToLower(); switch (cmd) { case "tx": case "transaction": { Hash hash; if (Hash.TryParse(input[1], out hash)) { InteropTransaction tx; if (platformName == DomainSettings.PlatformName) { var chain = Nexus.GetChainByName(chainName); var blockHash = chain.GetBlockHashOfTransaction(hash); var block = chain.GetBlockByHash(blockHash); var temp = chain.GetTransactionByHash(hash); if (block == null || temp == null) { throw new OracleException($"invalid transaction hash for chain {chainName} @ {platformName}"); } var events = block.GetEventsForTransaction(hash); var transfers = new List <InteropTransfer>(); foreach (var evt in events) { switch (evt.Kind) { case EventKind.TokenSend: { var data = evt.GetContent <TokenEventData>(); Event other; if (FindMatchingEvent(events, out other, (x) => { if (x.Kind != EventKind.TokenReceive && x.Kind != EventKind.TokenStake) { return(false); } var y = x.GetContent <TokenEventData>(); return(y.Symbol == data.Symbol && y.Value == data.Value); })) { var otherData = other.GetContent <TokenEventData>(); byte[] rawData = null; var token = Nexus.GetTokenInfo(Nexus.RootStorage, data.Symbol); if (!token.IsFungible()) { Event nftEvent; if (!FindMatchingEvent(events, out nftEvent, (x) => { if (x.Kind != EventKind.PackedNFT) { return(false); } var y = x.GetContent <PackedNFTData>(); return(y.Symbol == data.Symbol); })) { throw new OracleException($"invalid nft transfer with hash in chain {chainName} @ {platformName}"); } rawData = nftEvent.Data; } transfers.Add(new InteropTransfer(data.ChainName, evt.Address, otherData.ChainName, other.Address, Address.Null, data.Symbol, data.Value, rawData)); } break; } } } tx = new InteropTransaction(hash, transfers); if (typeof(T) == typeof(byte[])) { return(Serialization.Serialize(tx) as T); } } else { tx = PullPlatformTransaction(platformName, chainName, hash); if (tx == null) { return(null); } } if (typeof(T) == typeof(byte[])) { return(Serialization.Serialize(tx) as T); } return(tx as T); } else { throw new OracleException($"invalid transaction hash for chain {chainName} @ {platformName}"); } } case "block": { Hash hash; InteropBlock block; NativeBigInt height; // if it fails it might be block height if (Hash.TryParse(input[1], out hash)) { if (platformName == DomainSettings.PlatformName) { var chain = Nexus.GetChainByName(chainName); var temp = chain.GetBlockByHash(hash); if (temp == null) { throw new OracleException($"invalid block hash for chain {chainName} @ {platformName}"); } block = new InteropBlock(platformName, chainName, hash, temp.TransactionHashes); } else { block = PullPlatformBlock(platformName, chainName, hash); } if (typeof(T) == typeof(byte[])) { return(Serialization.Serialize(block) as T); } return((block) as T); } //TODO else if (NativeBigInt.TryParse(input[1], out height)) { if (platformName == DomainSettings.PlatformName) { var chain = Nexus.GetChainByName(chainName); var temp = chain.GetBlockByHash(hash); if (temp == null) { throw new OracleException($"invalid block hash for chain {chainName} @ {platformName}"); } block = new InteropBlock(platformName, chainName, hash, temp.TransactionHashes); } else { block = PullPlatformBlock(platformName, chainName, Hash.Null, height); } if (typeof(T) == typeof(byte[])) { return(Serialization.Serialize(block) as T); } return((block) as T); } else { throw new OracleException($"invalid block hash for chain {chainName} @ {platformName}"); } } default: throw new OracleException("unknown platform oracle"); } }