示例#1
0
 public DeployContract(IClient client)
 {
     this.client                 = client;
     this.ethSendTransaction     = new EthSendTransaction(client);
     this.constructorCallEncoder = new ConstructorCallEncoder();
     this.abiDeserialiser        = new ABIDeserialiser();
 }
示例#2
0
        /// <summary>
        ///同步 发送交易,返回交易回执
        /// </summary>
        /// <param name="abi">合约abi</param>
        /// <param name="contractAddress">合约地址</param>
        /// <param name="functionName">合约请求调用方法名称</param>
        /// <param name="inputsParameters">方法对应的 参数</param>
        /// <param name="value">请求参数值</param>
        /// <returns>交易回执</returns>
        public ReceiptResultDto SendTranscationWithReceipt(string abi, string contractAddress, string functionName, Parameter[] inputsParameters, params object[] value)
        {
            ReceiptResultDto receiptResult = new ReceiptResultDto();

            var des      = new ABIDeserialiser();
            var contract = des.DeserialiseContract(abi);

            var function            = contract.Functions.FirstOrDefault(x => x.Name == functionName);
            var sha3Signature       = function.Sha3Signature;// "0x53ba0944";
            var functionCallEncoder = new FunctionCallEncoder();
            var result = functionCallEncoder.EncodeRequest(sha3Signature, inputsParameters,
                                                           value);
            var blockNumber = GetBlockNumber();
            var transDto    = BuildTransactionParams(result, blockNumber, contractAddress);
            var tx          = BuildRLPTranscation(transDto);

            tx.Sign(new EthECKey(this._privateKey.HexToByteArray(), true));
            var txHash = SendRequest <object>(tx.Data, tx.Signature);

            if (txHash != null)
            {
                receiptResult = GetTranscationReceipt(txHash.ToString());
            }
            return(receiptResult);
        }
        /// <summary>
        /// 异步 Call 调用 适用于链上调用但不需要共识(通常用constant,view等修饰的合约方法)
        /// </summary>
        /// <param name="contractAddress">合约地址</param>
        /// <param name="abi">合约abi</param>
        /// <param name="callFunctionName">调用方法名称</param>
        /// <returns>返回交易回执</returns>
        public async Task <ReceiptResultDto> CallRequestAsync(string contractAddress, string abi, string callFunctionName, Parameter[] inputsParameters = null, params object[] value)
        {
            CallInput callDto = new CallInput();

            callDto.From = new Account(this._privateKey).Address.ToLower();//address ;
            var contractAbi = new ABIDeserialiser().DeserialiseContract(abi);

            callDto.To    = contractAddress;
            callDto.Value = new HexBigInteger(0);
            var function = contractAbi.Functions.FirstOrDefault(x => x.Name == callFunctionName);

            var sha3Signature = function.Sha3Signature;// "0x53ba0944";

            if (inputsParameters == null)
            {
                callDto.Data = "0x" + sha3Signature;
            }
            else
            {
                var functionCallEncoder = new FunctionCallEncoder();
                var funcData            = functionCallEncoder.EncodeRequest(sha3Signature, inputsParameters,
                                                                            value);
                callDto.Data = funcData;
            }
            var getRequest = new RpcRequest(this._requestId, JsonRPCAPIConfig.Call, new object[] { this._requestObjectId, callDto });
            var result     = await this._rpcClient.SendRequestAsync <ReceiptResultDto>(getRequest);

            //var getRequest = new RpcRequestMessage(this.RequestId, JsonRPCAPIConfig.Call, new object[] { this.RequestObjectId, callDto });
            //var result = HttpUtils.RpcPost<ReceiptResultDto>(BaseConfig.DefaultUrl, getRequest); //同步方法
            return(result);
        }
示例#4
0
        /// <summary>
        ///异步 发送交易,返回交易回执
        /// </summary>
        /// <param name="abi">合约abi</param>
        /// <param name="contractAddress">合约地址</param>
        /// <param name="functionName">合约请求调用方法名称</param>
        /// <param name="inputsParameters">方法对应的 参数</param>
        /// <param name="value">请求参数值</param>
        /// <returns>交易回执</returns>
        public async Task <ReceiptResultDto> SendTranscationWithReceiptAsync(string abi, string contractAddress, string functionName, Parameter[] inputsParameters, params object[] value)
        {
            ReceiptResultDto receiptResult = new ReceiptResultDto();

            var des                 = new ABIDeserialiser();
            var contract            = des.DeserialiseContract(abi);
            var function            = contract.Functions.FirstOrDefault(x => x.Name == functionName);
            var sha3Signature       = function.Sha3Signature;// "0x53ba0944";
            var functionCallEncoder = new FunctionCallEncoder();
            var result              = functionCallEncoder.EncodeRequest(sha3Signature, inputsParameters,
                                                                        value);
            var blockNumber = await GetBlockNumberAsync();

            var transDto = BuildTransactionParams(result, blockNumber, contractAddress);
            var tx       = BuildRLPTranscation(transDto);

            tx.Sign(new EthECKey(this._privateKey.HexToByteArray(), true));
            var txHash = await SendRequestAysnc <string>(tx.Data, tx.Signature);

            if (txHash != null)
            {
                receiptResult = await GetTranscationReceiptAsync(txHash);

                if (receiptResult == null)
                {
                    throw new Exception("txHash != null 的时候报错了:" + receiptResult.ToJson());
                }
            }
            return(receiptResult);
        }
示例#5
0
 public Contract(IClient client, string abi, string contractAddress)
 {
     ContractABI  = new ABIDeserialiser().DeserialiseContract(abi);
     Client       = client;
     Address      = contractAddress;
     ethNewFilter = new EthNewFilter(client);
 }
示例#6
0
        /// <summary>
        /// 同步 通用合约部署,只返回交易Hash
        /// </summary>
        /// <param name="binCode">合约内容</param>
        /// <returns>交易Hash</returns>
        public string DeployContract(string binCode, string abi = null, params object[] values)
        {
            var blockNumber = GetBlockNumber();
            var resultData  = "";
            ConstructorCallEncoder _constructorCallEncoder = new ConstructorCallEncoder();

            var des      = new ABIDeserialiser();
            var contract = des.DeserialiseContract(abi);

            if (contract.Constructor != null)
            {
                if (values != null)
                {
                    resultData = _constructorCallEncoder.EncodeRequest(binCode,
                                                                       contract.Constructor.InputParameters, values);
                }
                else
                {
                    resultData = _constructorCallEncoder.EncodeRequest(binCode, "");
                }
            }
            else
            {
                resultData = binCode;
            }
            var transParams = BuildTransactionParams(resultData, blockNumber, "");
            var tx          = BuildRLPTranscation(transParams);

            tx.Sign(new EthECKey(this._privateKey.HexToByteArray(), true));
            var result = SendRequest <object>(tx.Data, tx.Signature);

            return(Convert.ToString(result));
        }
        /// <summary>
        /// 异步 通用合约部署,只返回交易Hash
        /// </summary>
        /// <param name="binCode">合约内容</param>
        /// <returns>交易Hash</returns>
        public async Task <string> DeployContractAsync(string binCode, string abi = null, params object[] values)
        {
            var blockNumber = await GetBlockNumberAsync();

            var resultData = "";
            ConstructorCallEncoder _constructorCallEncoder = new ConstructorCallEncoder();

            if (values == null || values.Length == 0)
            {
                resultData = _constructorCallEncoder.EncodeRequest(binCode, "");
            }

            var des      = new ABIDeserialiser();
            var contract = des.DeserialiseContract(abi);

            if (contract.Constructor == null)
            {
                throw new Exception(
                          "Parameters supplied for a constructor but ABI does not contain a constructor definition");
            }
            resultData = _constructorCallEncoder.EncodeRequest(binCode,
                                                               contract.Constructor.InputParameters, values);

            var transParams = BuildTransactionParams(resultData, blockNumber, "");
            var tx          = BuildRLPTranscation(transParams);

            tx.Sign(new EthECKey(this._privateKey.HexToByteArray(), true));
            var result = await SendRequestAysnc <string>(tx.Data, tx.Signature);

            return(result);
        }
 public DeployContract(IClient client)
 {
     this.client                    = client;
     ethSendTransaction             = new EthSendTransaction(client);
     personalSignAndSendTransaction = new PersonalSignAndSendTransaction(client);
     constructorCallEncoder         = new ConstructorCallEncoder();
     abiDeserialiser                = new ABIDeserialiser();
 }
示例#9
0
        public void ShouldDeserialisedAndEncodeSignatureEventsWithTuples()
        {
            var abi         = "[{\"constant\":false,\"inputs\":[],\"name\":\"txRaiseEvent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"truncateToLength\",\"type\":\"uint256\"}],\"name\":\"bytes32ToString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"source\",\"type\":\"string\"}],\"name\":\"stringToBytes32\",\"outputs\":[{\"name\":\"result\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"buyerSysId\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"buyerPurchaseOrderNumber\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"buyerProductId\",\"type\":\"bytes32\"},{\"components\":[{\"name\":\"ethPurchaseOrderNumber\",\"type\":\"uint64\"},{\"name\":\"buyerSysId\",\"type\":\"bytes32\"},{\"name\":\"buyerPurchaseOrderNumber\",\"type\":\"bytes32\"},{\"name\":\"sellerSysId\",\"type\":\"bytes32\"},{\"name\":\"sellerSalesOrderNumber\",\"type\":\"bytes32\"},{\"name\":\"buyerProductId\",\"type\":\"bytes32\"},{\"name\":\"sellerProductId\",\"type\":\"bytes32\"},{\"name\":\"currency\",\"type\":\"bytes32\"},{\"name\":\"currencyAddress\",\"type\":\"address\"},{\"name\":\"totalQuantity\",\"type\":\"uint32\"},{\"name\":\"totalValue\",\"type\":\"uint32\"},{\"name\":\"openInvoiceQuantity\",\"type\":\"uint32\"},{\"name\":\"openInvoiceValue\",\"type\":\"uint32\"},{\"name\":\"poStatus\",\"type\":\"uint8\"}],\"indexed\":false,\"name\":\"purchaseOrder\",\"type\":\"tuple\"}],\"name\":\"PurchaseRaisedLog\",\"type\":\"event\"}]";
            var contractAbi = new ABIDeserialiser().DeserialiseContract(abi);
            var eventAbi    = contractAbi.Events.FirstOrDefault(e => e.Name == "PurchaseRaisedLog");

            Assert.Equal("8004ab55fa321fe77c5bde5420bc7af7d33f755d3d71ee4d59bf0c0af7b9c055", eventAbi.Sha3Signature);
        }
示例#10
0
 public ABIService(
     IABIRepository abiRepository,
     ILogFactory logFactory)
 {
     _abiDeserializer = new ABIDeserialiser();
     _abiRepository   = abiRepository;
     _log             = logFactory.CreateLog(this);
 }
示例#11
0
        public void ShouldDeserialiseJArrayStyleABI()
        {
            var abi         = "[{\"constant\":false,\"inputs\":[{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"productId\",\"type\":\"uint256\"},{\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"lineItem\",\"type\":\"tuple[]\"},{\"name\":\"customerId\",\"type\":\"uint256\"}],\"name\":\"purchaseOrder\",\"type\":\"tuple\"}],\"name\":\"SetPurchaseOrder\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"GetPurchaseOrder2\",\"outputs\":[{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"productId\",\"type\":\"uint256\"},{\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"lineItem\",\"type\":\"tuple[]\"},{\"name\":\"customerId\",\"type\":\"uint256\"}],\"name\":\"purchaseOrder\",\"type\":\"tuple\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetPurchaseOrder\",\"outputs\":[{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"productId\",\"type\":\"uint256\"},{\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"lineItem\",\"type\":\"tuple[]\"},{\"name\":\"customerId\",\"type\":\"uint256\"}],\"name\":\"purchaseOrder\",\"type\":\"tuple\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"productId\",\"type\":\"uint256\"},{\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"lineItem\",\"type\":\"tuple[]\"},{\"name\":\"customerId\",\"type\":\"uint256\"}],\"indexed\":false,\"name\":\"purchaseOrder\",\"type\":\"tuple\"}],\"name\":\"PurchaseOrderChanged\",\"type\":\"event\"}]";
            var contractAbi = new ABIDeserialiser().DeserialiseContract(JArray.Parse(abi));
            var functionABI = contractAbi.Functions.FirstOrDefault(e => e.Name == "SetPurchaseOrder");
            var sig         = functionABI.Sha3Signature;

            Assert.Equal("0cc400bd", functionABI.Sha3Signature);
        }
        public string ContractGen(string abi, string contractName, string nameSpace)
        {
            contractName = MakeFirstCharUpper(contractName);
            var des         = new ABIDeserialiser();
            var contract    = des.DeserialiseContract(abi);
            var operations  = EventsGen(contract) + FunctionsGen(contract);
            var genContract = string.Format(ContractTemplate, abi.Replace("\"", "\"\""), contractName, operations);

            return(string.Format(NameSpaceTemplate, nameSpace, genContract));
        }
示例#13
0
        public async Task VerifyFunctionCall <T>(string abi, string contractAddress, string functionName, T expectedResult, params object[] values)
        {
            var contractABI = new ABIDeserialiser().DeserialiseContract(abi);
            var functionABI = contractABI.Functions.FirstOrDefault(x => x.Name == functionName && x.InputParameters.Length == values.Length);

            var contract = web3.Eth.GetContract(abi, contractAddress);
            T   result   = await contract.GetFunctionBySignature(functionABI.Sha3Signature).CallAsync <T>(values);

            result.Should().BeEquivalentTo(expectedResult, $"The result of function call {functionName} is not expected");
        }
示例#14
0
        public ServiceModel(string abi, string byteCode, string contractName = DEFAULT_CONTRACTNAME,
                            string namespaceName = DEFAULT_NAMESPACE)
        {
            ContractName = CapitaliseFirstChar(contractName);
            Namespace    = CapitaliseFirstChar(namespaceName);
            Abi          = abi;
            ByteCode     = byteCode;
            var des = new ABIDeserialiser();

            Contract = des.DeserialiseContract(abi);
        }
示例#15
0
        public CommonModel(string abi, string byteCode,
                           string namespaceName = DEFAULT_NAMESPACE)
        {
            utils       = new Utils();
            GlobalNames = new GlobalNames();
            Namespace   = Utils.CapitaliseFirstChar(namespaceName);
            Abi         = abi;
            ByteCode    = byteCode;
            var des = new ABIDeserialiser();

            Contract = des.DeserialiseContract(abi);
        }
示例#16
0
        /// <summary>
        /// 同步 Call 调用 适用于链上调用但不需要共识(通常用constant,view等修饰的合约方法)
        /// </summary>
        /// <param name="contractAddress">合约地址</param>
        /// <param name="abi">合约abi</param>
        /// <param name="callFunctionName">调用方法名称</param>
        /// <returns>返回交易回执</returns>
        public ReceiptResultDto CallRequest(string contractAddress, string abi, string callFunctionName)
        {
            CallInput callDto = new CallInput();

            callDto.From = new Account(this._privateKey).Address.ToLower();//address ;
            callDto.To   = contractAddress;
            var contractAbi = new ABIDeserialiser().DeserialiseContract(abi);
            var function    = contractAbi.Functions.FirstOrDefault(x => x.Name == callFunctionName);

            callDto.Value = new HexBigInteger(0);
            callDto.Data  = "0x" + function.Sha3Signature;
            var request = new RpcRequestMessage(this._requestId, JsonRPCAPIConfig.Call, new object[] { this._requestObjectId, callDto });
            var result  = HttpUtils.RpcPost <ReceiptResultDto>(this._url, request);;

            return(result);
        }
示例#17
0
        public virtual void ShouldDeserializeContract()
        {
            string abi = @"[{""constant"":false,""inputs"":[{""name"":""a"",""type"":""uint256""}],""name"":""multiply"",""outputs"":[{""name"":""d"",""type"":""uint256""}],""type"":""function""},{""constant"":false,""inputs"":[{""name"":""a"",""type"":""uint256""},{""name"":""to"",""type"":""address""}],""name"":""other"",""outputs"":[{""name"":""d"",""type"":""uint256""}],""type"":""function""}]";

            var des      = new ABIDeserialiser();
            var contract = des.DeserialiseContract(abi);
            var function = contract.Functions.FirstOrDefault(x => x.Name == "multiply");

            Assert.NotNull(function);
            Assert.False(function.Constant);
            var param = function.InputParameters.FirstOrDefault(x => x.Name == "a");

            Assert.NotNull(param);
            Assert.Equal(param.Type, "uint256");
            Assert.Equal("c6888fa1", function.Sha3Signature);
            Assert.Equal("ea6ace3d", contract.Functions[1].Sha3Signature);
        }
示例#18
0
        public async Task QueueAllEventsForMakerDAOContract()
        {
            // Load config
            //  - this will contain the secrets and connection strings we don't want to hard code
            var    config = TestConfiguration.LoadConfig();
            string azureStorageConnectionString = config["AzureStorageConnectionString"];

            // Create a proxy for the blockchain
            var web3 = new Web3.Web3(TestConfiguration.BlockchainUrls.Infura.Mainnet);

            // Create Queue Factory
            //  - In this sample we're targetting Azure
            //  - The factory communicates with Azure to create and get different queues
            var queueFactory = new AzureSubscriberQueueFactory(azureStorageConnectionString);
            // Create a Queue
            //  - This is where we're going to put the matching event logs
            var queue = await queueFactory.GetOrCreateQueueAsync("makerdaoevents");

            //  Get the maker DAO contract abi
            //  - from this we're able to match and decode the events in the contract
            var contractAbi = new ABIDeserialiser().DeserialiseContract(MAKER_DAO_ABI);

            // Create an event subscription for these events
            // - Passing in the maker dao address to ensure only logs with a matching address are processed
            // - There is an option to pass an implementation of IEventHandlerHistoryRepository in to the constructor
            // - This would record history for each event handler and is used to prevent duplication
            var eventSubscription = new EventSubscription(contractAbi.Events, new[] { MAKER_CONTRACT_ADDRESS });

            // Assign the queue to the event subscription
            // - Matching events will be written to this queue
            // - By default a generic message is written to the queue
            // - The message contains the raw log (aka FilterLog), decoded event parameter values and event metadata
            // - Therefore the message schema is consistent across all messages sent to any queues
            // - However - should you require your own queue message schema the method below accepts a custom message mapper
            // - Ultimately the message is converted to json
            eventSubscription.AddQueueHandler(queue);

            // Azure storage setup
            // - this example reads and writes block progress to an Azure storage table
            // - to avoid collision with other samples we provide a prefix
            var storageCloudSetup = new CloudTableSetup(azureStorageConnectionString, prefix: $"makerdao");

            // Create a progress repository
            //  - It stores and retrieves the most recent block processed
            var blockProgressRepo = storageCloudSetup.CreateBlockProgressRepository();

            // Create a progress service
            // - This uses the progress repo to dictate what blocks to process next
            // - The MIN_BLOCK_NUMBER dictates the starting point if the progress repo is empty or has fallen too far behind
            var progressService = new BlockProgressService(web3, MIN_BLOCK_NUMBER, blockProgressRepo);

            // Create a filter
            //  - This is essentially the query that is sent to the chain when retrieving logs
            //  - It is OPTIONAL - without it, all logs in the block range are requested
            //  - The filter is invoked before any event subscriptions evaluate the logs
            //  - The subscriptions are free to implement their own matching logic
            //  - In this sample we're only interested in MakerDAO logs
            //  - Therefore it makes sense to restrict the number of logs to retrieve from the chain
            var makerAddressFilter = new NewFilterInput()
            {
                Address = new[] { MAKER_CONTRACT_ADDRESS }
            };

            // Create a log processor
            // - This uses the blockchainProxy to get the logs
            // - It sends each log to the event subscriptions to indicate if the logs matches the subscription criteria
            // - It then allocates matching logs to separate batches per event subscription
            var logProcessor = new BlockRangeLogsProcessor(web3, new[] { eventSubscription }, makerAddressFilter);

            // Create a batch log processor service
            // - It uses the progress service to calculates the block range to progress
            // - It then invokes the log processor - passing in the range to process
            // - It updates progress via the progress service
            var batchProcessorService = new LogsProcessor(logProcessor, progressService, MAX_BLOCKS_PER_BATCH);

            // execute
            try
            {
                // Optional cancellation token
                // - Useful for cancelling long running processing operations
                var ctx = new System.Threading.CancellationTokenSource();

                // instruct the service to get and process the next range of blocks
                // when the rangeProcessed is null - it means there was nothing to process
                var rangeProcessed = await batchProcessorService.ProcessOnceAsync(ctx.Token);

                // ensure we have processed the expected number of events
                // the event subscription has state which can record running totals across many processing batches
                Assert.Equal(16, eventSubscription.State.GetInt("EventsHandled"));
                // get the message count from the queue
                Assert.Equal(16, await queue.GetApproxMessageCountAsync());
            }
            finally
            {
                // delete any data from Azure
                await ClearDown(queue, storageCloudSetup, queueFactory);
            }
        }
示例#19
0
 public DeployContract(ITransactionManager transactionManager)
 {
     TransactionManager      = transactionManager;
     _constructorCallEncoder = new ConstructorCallEncoder();
     _abiDeserialiser        = new ABIDeserialiser();
 }
示例#20
0
 public ContractBuilder(string abi, string contractAddress)
 {
     ContractABI = new ABIDeserialiser().DeserialiseContract(abi);
     Address     = contractAddress;
 }
        public async Task WriteAllEventsForMakerDAOToAzureStorage()
        {
            // Load config
            //  - this will contain the secrets and connection strings we don't want to hard code
            var    config = TestConfiguration.LoadConfig();
            string azureStorageConnectionString = config["AzureStorageConnectionString"];

            // Create a proxy for the blockchain
            //  - It will get the logs from the chain
            //  - It provides a log processing friendly abstraction
            //  - Under the hood it wraps the Nethereum.Web3.Web3 object
            //  - In this sample we're hardcoded to target mainnet
            var web3 = new Web3.Web3(TestConfiguration.BlockchainUrls.Infura.Mainnet);

            //  Get the maker DAO contract abi
            //  - from this we're able to match and decode the events in the contract
            var contractAbi = new ABIDeserialiser().DeserialiseContract(MAKER_DAO_ABI);

            // Create an event subscription for these events
            // - Passing in the maker dao address to ensure only logs with a matching address are processed
            // - There is an option to pass an implementation of IEventHandlerHistoryRepository in to the constructor
            // - This would record history for each event handler and is used to prevent duplication
            var eventSubscription = new EventSubscription(contractAbi.Events, new[] { MAKER_CONTRACT_ADDRESS });

            // Create an Azure Table Storage Factory
            //  - The factory communicates with Azure to create and get different tables
            var tableStorageFactory = new AzureTablesSubscriberRepositoryFactory(azureStorageConnectionString);

            // Create a Handler for a Table
            // - It wraps a table repository (routing ILogHandler calls to ITransactionLogRepository)
            // - This is where we're going to put the matching event logs
            // - we're supplying a table prefix
            // - the actual table name would be "<prefix>TransactionLogs"
            // - this allows us to have different tables for different groups of event logs
            // - the handler implements ILogHandler
            // - ILogHandler is a really simple interface to implement if you wish to customise the storage
            var storageHandlerForLogs = await tableStorageFactory.GetLogRepositoryHandlerAsync(tablePrefix : "makerdaoalleventstorage");

            // Assign the storage handler to the event subscription
            // - Matching events will be passed to the handler
            // - internally the handler passes the events to the repository layer which writes them to Azure
            eventSubscription.AddStorageHandler(storageHandlerForLogs);

            // Azure storage setup (for storing Block Progress)
            // - this example reads and writes block progress to an Azure storage table
            // - to avoid collision with other samples we provide a prefix
            var storageCloudSetup = new CloudTableSetup(azureStorageConnectionString, prefix: $"makerdaoalleventstorage");

            // Create a progress repository
            //  - It stores and retrieves the most recent block processed
            var blockProgressRepo = storageCloudSetup.CreateBlockProgressRepository();

            // Create a progress service
            // - This uses the progress repo to dictate what blocks to process next
            // - The MIN_BLOCK_NUMBER dictates the starting point if the progress repo is empty or has fallen too far behind
            var progressService = new BlockProgressService(web3, MIN_BLOCK_NUMBER, blockProgressRepo);

            // Create a filter
            //  - This is essentially the query that is sent to the chain when retrieving logs
            //  - It is OPTIONAL - without it, all logs in the block range are requested
            //  - The filter is invoked before any event subscriptions evaluate the logs
            //  - The subscriptions are free to implement their own matching logic
            //  - In this sample we're only interested in MakerDAO logs
            //  - Therefore it makes sense to restrict the number of logs to retrieve from the chain
            var makerAddressFilter = new NewFilterInput()
            {
                Address = new[] { MAKER_CONTRACT_ADDRESS }
            };

            // Create a log processor
            // - This uses the blockchainProxy to get the logs
            // - It sends each log to the event subscriptions to indicate if the logs matches the subscription criteria
            // - It then allocates matching logs to separate batches per event subscription
            var logProcessor = new BlockRangeLogsProcessor(web3, new[] { eventSubscription }, makerAddressFilter);

            // Create a batch log processor service
            // - It uses the progress service to calculates the block range to progress
            // - It then invokes the log processor - passing in the range to process
            // - It updates progress via the progress service
            var batchProcessorService = new LogsProcessor(logProcessor, progressService, MAX_BLOCKS_PER_BATCH);

            // execute
            try
            {
                // Optional cancellation token
                // - Useful for cancelling long running processing operations
                var ctx = new System.Threading.CancellationTokenSource();

                // instruct the service to get and process the next range of blocks
                // when the rangeProcessed is null - it means there was nothing to process
                var rangeProcessed = await batchProcessorService.ProcessOnceAsync(ctx.Token);

                // ensure we have processed the expected number of events
                // the event subscription has state which can record running totals across many processing batches
                Assert.Equal(16, eventSubscription.State.GetInt("EventsHandled"));

                // get the row count from azure storage
                // querying azure table storage is limited/basic
                // the TransactionHash is the partitionkey and the rowkey is the LogIndex
                // this allows us to query by tx hash

                var logRepositoryHandler = storageHandlerForLogs as TransactionLogRepositoryHandler;
                var repository           = logRepositoryHandler.TransactionLogRepository as TransactionLogRepository;

                var expectedTransactionHashes = new[]
                {
                    "0x19db52e6f823b39aa1763321514a3f4a07c66140b90d99bc28b7f4bc318e0c9c",
                    "0x8d58abc578f5e321f2e6b7c0637ccc60fbf62b39b120691cbf19ff201f5069b0",
                    "0x2a7da4088595861792bcd6c4201bcacc8e93e4b931a9254da82594cd42ca9993",
                    "0x0bee561ac6bafb59bcc4c48fc4c1225aaedbab3e8089acea420140aafa47f3e5",
                    "0x6fc82b076fa7088581a80869cb9c7a08d7f8e897670a9f67e39139b39246da7e",
                    "0xdc2ee28db35ed5dbbc9e18a7d6bdbacb6e6633a9fce1ecda99ea7e1cf4bc8c72",
                    "0xcd2fea48c84468f70c9a44c4ffd7b26064a2add8b72937edf593634d2501c1f6",
                    "0x3acf887420887148222aab1d25d4d4893794e505ef276cc4cb6a48fffc6cb381",
                    "0x96129f905589b2a95c26276aa7e8708a12381ddec50485d6684c4abf9a5a1d00"
                };

                List <TransactionLog> logsFromRepo = new List <TransactionLog>();
                foreach (var txHash in expectedTransactionHashes)
                {
                    logsFromRepo.AddRange(await repository.GetManyAsync(txHash));
                }

                Assert.Equal(16, logsFromRepo.Count);
            }
            finally
            {
                // delete any data from Azure
                await storageCloudSetup.GetCountersTable().DeleteIfExistsAsync();

                await tableStorageFactory.DeleteTablesAsync();
            }
        }
示例#22
0
 public Contract(EthApiService eth, string abi, string contractAddress)
 {
     Eth         = eth;
     ContractABI = new ABIDeserialiser().DeserialiseContract(abi);
     Address     = contractAddress;
 }
示例#23
0
 public DecodingService()
 {
     _abiDeserializer     = new ABIDeserialiser();
     _eventTopicDecoder   = new EventTopicDecoder();
     _functionCallDecoder = new FunctionCallDecoder();
 }
示例#24
0
 public DeployContractTransactionBuilder()
 {
     _constructorCallEncoder = new ConstructorCallEncoder();
     _abiDeserialiser        = new ABIDeserialiser();
 }