// NOTE: That says "po-Op-Source", but if you want to look at it as "poOp-Source", well, that's up to you, // and try not laugh yourself silly public void AddCustomOperator(string psCustomOpName, WonkaBreSource poOpSource = null) { if (BasicOps.Contains(psCustomOpName)) { throw new Exception("ERROR! Provided operator is already a basic operator within the rules engine."); } if (ArithmeticLimitOps.Contains(psCustomOpName)) { throw new Exception("ERROR! Provided operator is already a arithmetic limit operator within the rules engine."); } if (DateLimitOps.Contains(psCustomOpName)) { throw new Exception("ERROR! Provided operator is already a date limit operator within the rules engine."); } if (poOpSource != null) { CustomOpSources[psCustomOpName] = poOpSource; } else { CustomOpSources[psCustomOpName] = new WonkaBreSource("", "", "", "", "", "", "", null); } }
public WonkaBreRulesEngine(StringBuilder psRules, Dictionary <string, WonkaBreSource> poSourceMap, Dictionary <string, WonkaBreSource> poCustomOpBlockchainSources, IMetadataRetrievable piMetadataSource = null, bool pbAddToRegistry = true) { if ((psRules == null) || (psRules.Length <= 0)) { throw new WonkaBreException("ERROR! Provided rules are null or empty!"); } UsingOrchestrationMode = true; AddToRegistry = pbAddToRegistry; RefEnvHandle = Init(piMetadataSource); WonkaBreXmlReader BreXmlReader = new WonkaBreXmlReader(psRules, piMetadataSource, this); foreach (string sKey in poCustomOpBlockchainSources.Keys) { WonkaBreSource oTargetSource = poCustomOpBlockchainSources[sKey]; BreXmlReader.AddCustomOperator(sKey, oTargetSource); } RuleTreeRoot = BreXmlReader.ParseRuleTree(); SourceMap = poSourceMap; CustomOpMap = poCustomOpBlockchainSources; AllRuleSets = BreXmlReader.AllParsedRuleSets; this.RetrieveCurrRecord = AssembleCurrentProduct; }
public CustomOperatorRule(int pnRuleID, TARGET_RECORD peTargetRecord, int pnTargetAttrId, string psCustomOpName, WonkaBreXmlReader.ExecuteCustomOperator poCustomOpDelegate, WonkaBreSource poCustomOpContractSource) : base(pnRuleID, RULE_TYPE.RT_CUSTOM_OP) { Init(peTargetRecord, pnTargetAttrId, null); CustomOpName = psCustomOpName; CustomOpDelegate = poCustomOpDelegate; CustomOpContractSource = poCustomOpContractSource; }
public Nethereum.Contracts.Contract GetContract(WonkaBreSource poBlockchainSource) { var account = new Account(poBlockchainSource.Password); Nethereum.Web3.Web3 web3 = null; if ((moInitData != null) && !String.IsNullOrEmpty(moInitData.Web3HttpUrl)) { web3 = new Nethereum.Web3.Web3(account, moInitData.Web3HttpUrl); } else { web3 = new Nethereum.Web3.Web3(account); } var contract = web3.Eth.GetContract(poBlockchainSource.ContractABI, poBlockchainSource.ContractAddress); return(contract); }
/// <summary> /// /// This method will assemble the new product by iterating through each specified source /// and retrieving the data from it. /// /// <param name="poKeyValues">The keys for the product whose data we wish to extract/param> /// <returns>Contains the assembled product data that represents the current product</returns> /// </summary> public WonkaProduct AssembleCurrentProduct(Dictionary <string, string> poKeyValues) { WonkaProduct CurrentProduct = new WonkaProduct(); // NOTE: Do work here if (SourceMap != null) { foreach (string sTmpAttName in SourceMap.Keys) { WonkaBreSource TmpSource = SourceMap[sTmpAttName]; WonkaRefAttr TargetAttr = RefEnvHandle.GetAttributeByAttrName(sTmpAttName); string sTmpValue = TmpSource.RetrievalDelegate.Invoke(TmpSource, TargetAttr.AttrName); CurrentProduct.SetAttribute(TargetAttr, sTmpValue); } } return(CurrentProduct); }
public virtual void SerializeRecordToBlockchain(ICommand poCommand) { Hashtable DataValues = new Hashtable(); GetPropertiesViaReflection(poCommand, DataValues); Dictionary <string, Contract> Sources = new Dictionary <string, Contract>(); foreach (string sAttrName in moRulesEngine.SourceMap.Keys) { var contract = this.GetContract(moRulesEngine.SourceMap[sAttrName]); Sources[moRulesEngine.SourceMap[sAttrName].SourceId] = contract; } // Out of gas exception // var gas = setValueOnRecordFunction.EstimateGasAsync(sSenderAddress, "SomeAttr", "SomeValue").Result; var gas = new Nethereum.Hex.HexTypes.HexBigInteger(1000000); foreach (String sTempAttrName in DataValues.Keys) { WonkaBreSource TempSource = moRulesEngine.SourceMap[sTempAttrName]; string sSenderAddr = TempSource.SenderAddress; string sAttrValue = (string)DataValues[sTempAttrName]; var contract = Sources[TempSource.SourceId]; var setValueOnRecordFunction = contract.GetFunction(TempSource.SetterMethodName); if (!String.IsNullOrEmpty(sAttrValue)) { var receiptSetValueOnRecord = setValueOnRecordFunction.SendTransactionAsync(sSenderAddr, gas, null, sTempAttrName, sAttrValue).Result; } } }
public virtual void DeserializeRecordFromBlockchain(ICommand poCommand) { Hashtable DataValues = new Hashtable(); Dictionary <string, Contract> Sources = new Dictionary <string, Contract>(); foreach (string sAttrName in moInitData.BlockchainDataSources.Keys) { var contract = this.GetContract(moInitData.BlockchainDataSources[sAttrName]); Sources[moInitData.BlockchainDataSources[sAttrName].SourceId] = contract; } // Out of gas exception // var gas = setValueOnRecordFunction.EstimateGasAsync(sSenderAddress, "SomeAttr", "SomeValue").Result; var gas = new Nethereum.Hex.HexTypes.HexBigInteger(1000000); foreach (String sTempAttrName in moInitData.BlockchainDataSources.Keys) { WonkaBreSource TempSource = moInitData.BlockchainDataSources[sTempAttrName]; string sSenderAddr = TempSource.SenderAddress; var contract = Sources[TempSource.SourceId]; var getValueOnRecordFunction = contract.GetFunction(TempSource.MethodName); string sAttrValue = getValueOnRecordFunction.CallAsync <string>(sTempAttrName).Result; if (!String.IsNullOrEmpty(sAttrValue)) { DataValues[sTempAttrName] = sAttrValue; } } AssignPropertiesViaReflection(poCommand, DataValues); }
public RuleTreeReport ExecuteWithReport(WonkaBreRulesEngine poRulesEngine, bool pbValidateWithinTransaction, WonkaBreSource poFlagSource) { WonkaRefEnvironment RefEnv = WonkaRefEnvironment.GetInstance(); WonkaRefAttr CurrValueAttr = RefEnv.GetAttributeByAttrName("AccountCurrValue"); WonkaRefAttr ReviewFlagAttr = RefEnv.GetAttributeByAttrName("AuditReviewFlag"); Dictionary <string, string> PrdKeys = new Dictionary <string, string>(); var contract = GetContract(); var executeWithReportFunction = contract.GetFunction(CONST_CONTRACT_FUNCTION_EXEC_RPT); RuleTreeReport ruleTreeReport = null; if (pbValidateWithinTransaction) { var executeGetLastReportFunction = contract.GetFunction(CONST_CONTRACT_FUNCTION_GET_LAST_RPT); // NOTE: Caused exception to be thrown // var gas = executeWithReportFunction.EstimateGasAsync(msSenderAddress).Result; var gas = new Nethereum.Hex.HexTypes.HexBigInteger(1000000); WonkaProduct OrchContractCurrValues = poRulesEngine.AssembleCurrentProduct(new Dictionary <string, string>()); string sFlagBeforeOrchestrationAssignment = RetrieveValueMethod(poFlagSource, ReviewFlagAttr.AttrName); string sValueBeforeOrchestrationAssignment = RetrieveValueMethod(poFlagSource, CurrValueAttr.AttrName); var receiptAddAttribute = executeWithReportFunction.SendTransactionAsync(msSenderAddress, gas, null, msSenderAddress).Result; string sFlagAfterOrchestrationAssignment = RetrieveValueMethod(poFlagSource, ReviewFlagAttr.AttrName); string sValueAfterOrchestrationAssignment = RetrieveValueMethod(poFlagSource, CurrValueAttr.AttrName); ruleTreeReport = executeGetLastReportFunction.CallDeserializingToObjectAsync <RuleTreeReport>().Result; } else { ruleTreeReport = executeWithReportFunction.CallDeserializingToObjectAsync <RuleTreeReport>(msSenderAddress).Result; } return(ruleTreeReport); }
public void Execute(string psOrchestrationTestAddress = null, bool pbValidateWithinTransaction = false) { WonkaRefEnvironment RefEnv = WonkaRefEnvironment.GetInstance(); Dictionary <string, WonkaBre.RuleTree.WonkaBreSource> SourceMap = new Dictionary <string, WonkaBre.RuleTree.WonkaBreSource>(); string sDefaultSource = "S"; string sContractSourceId = sDefaultSource; string sContractAddress = ""; string sContractAbi = ""; string sOrchGetterMethod = ""; string sOrchSetterMethod = ""; // If a 'psOrchestrationTestAddress' value has been provided, it indicates that the user wishes // to use Orchestration if (!String.IsNullOrEmpty(psOrchestrationTestAddress)) { // Here we set the values for Orchestration (like the target contract) and the implemented // methods that have the expected function signatures for getting/setting Attribute values sContractAddress = psOrchestrationTestAddress; sContractAbi = msAbiOrchTest; sOrchGetterMethod = "getAttrValueBytes32"; sOrchSetterMethod = "setAttrValueBytes32"; } else { sContractAddress = msContractAddress; sContractAbi = msAbiWonka; sOrchGetterMethod = "getValueOnRecord"; sOrchSetterMethod = ""; } // Here a mapping is created, where each Attribute points to a specific contract and its "accessor" methods // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type foreach (WonkaRefAttr TempAttr in moTargetAttrList) { WonkaBreSource TempSource = new WonkaBreSource(sContractSourceId, msSenderAddress, msPassword, sContractAddress, sContractAbi, sOrchGetterMethod, sOrchSetterMethod, RetrieveValueMethod); SourceMap[TempAttr.AttrName] = TempSource; } // Creating an instance of the rules engine using our rules and the metadata WonkaBreRulesEngine RulesEngine = null; if (psOrchestrationTestAddress == null) { RulesEngine = new WonkaBreRulesEngine(new StringBuilder(msRulesContents), moMetadataSource); } else { RulesEngine = new WonkaBreRulesEngine(new StringBuilder(msRulesContents), SourceMap, moMetadataSource); RulesEngine.DefaultSource = sDefaultSource; } RulesEngine.SetDefaultStdOps(msPassword); // The contract dictates that the RuleTree (and its other info, like the Source mapping) is serialized // to the blockchain before interacting with it SerializeRulesEngineToBlockchain(RulesEngine); WonkaRefAttr AccountStsAttr = RefEnv.GetAttributeByAttrName("AccountStatus"); WonkaRefAttr RvwFlagAttr = RefEnv.GetAttributeByAttrName("AuditReviewFlag"); // Gets a predefined data record that will be our analog for new data coming into the system // We are only using this record to test the .NET implementation WonkaProduct NewProduct = GetNewProduct(); string sStatusValueBefore = GetAttributeValue(NewProduct, AccountStsAttr); string sFlagValueBefore = GetAttributeValue(NewProduct, RvwFlagAttr); // SerializeProductToBlockchain(NewProduct); // Validate that the .NET implementation and the rules markup are both working properly WonkaBre.Reporting.WonkaBreRuleTreeReport Report = RulesEngine.Validate(NewProduct); string sStatusValueAfter = GetAttributeValue(NewProduct, AccountStsAttr); string sFlagValueAfter = GetAttributeValue(NewProduct, RvwFlagAttr); if (Report.OverallRuleTreeResult == ERR_CD.CD_SUCCESS) { // NOTE: This should only be used for further testing // Serialize(NewProduct); } else if (Report.GetRuleSetFailureCount() > 0) { System.Console.WriteLine(".NET Engine says \"Oh heavens to Betsy! Something bad happened!\""); } else { System.Console.WriteLine(".NET Engine says \"What in the world is happening?\""); } // If a 'psOrchestrationTestAddress' value has been provided, it indicates that the user wishes // to use Orchestration if (!String.IsNullOrEmpty(psOrchestrationTestAddress)) { /** ** Now execute the rules engine on the blockchain. ** ** NOTE: Based on the value of the argument 'pbValidateWithinTransaction', we will act accordingly - ** If set to 'true', we issue a call() when we execute the rules engine, since we are only ** looking to validate here. However, if the value if 'false', we issue a sendTransaction() ** so that we can attempts to set values (i.e., change the blockchain) will take effect. ** In that case, we might want to pull back the record afterwards with a subsequent function ** call, in order to examine the record here. ** **/ var BlockchainReport = ExecuteWithReport(RulesEngine, pbValidateWithinTransaction, SourceMap[RvwFlagAttr.AttrName]); if (BlockchainReport.NumberOfRuleFailures == 0) { // Indication of a success } else if (BlockchainReport.NumberOfRuleFailures > 0) { throw new Exception("Oh heavens to Betsy! Something bad happened!"); } else { throw new Exception("Seriously, what in the world is happening?!"); } } }
// This constructor will be called in the case that we wish to initialize the framework // with configuration files locally (embedded resources, local filesystem, etc.) public WonkaCQSOrchTest() { moAttrSourceMap = new Dictionary <string, WonkaBreSource>(); moCustomOpMap = new Dictionary <string, WonkaBreSource>(); var TmpAssembly = Assembly.GetExecutingAssembly(); // Using the metadata source, we create an instance of a defined data domain WonkaRefEnvironment RefEnv = WonkaRefEnvironment.CreateInstance(false, moMetadataSource); // Read the XML markup that lists the business rules (i.e., the RuleTree) using (var RulesReader = new StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.VATCalculationExample.xml"))) { msRulesContents = RulesReader.ReadToEnd(); } // Read the configuration file that contains all the initialization details regarding the rules engine // (like addresses of contracts, senders, passwords, etc.) using (var XmlReader = new System.IO.StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.VATCalculationExample.init.xml"))) { string sInitXml = XmlReader.ReadToEnd(); // We deserialize/parse the contents of the config file System.Xml.Serialization.XmlSerializer WonkaEthSerializer = new System.Xml.Serialization.XmlSerializer(typeof(WonkaEth.Init.WonkaEthInitialization), new System.Xml.Serialization.XmlRootAttribute("WonkaEthInitialization")); WonkaEth.Init.WonkaEthInitialization WonkaInit = WonkaEthSerializer.Deserialize(new System.IO.StringReader(sInitXml)) as WonkaEth.Init.WonkaEthInitialization; // Here, any embeddeded resources mentioned in the config file (instead of simple file URLs) are accessed here WonkaInit.RetrieveEmbeddedResources(TmpAssembly); // The initialization data is transformed into a structure used by the WonkaEth namespace moOrchInitData = WonkaInit.TransformIntoOrchestrationInit(moMetadataSource); System.Console.WriteLine("Number of custom operators: (" + WonkaInit.CustomOperatorList.Length + ")."); } // Read the configuration file that contains all the initialization details regarding the rules registry // (like Ruletree info, Grove info, etc.) - this information will allow us to add our RuleTree to the // Registry so that it can be discovered by users and so it can be added to a Grove (where it can be executed // as a member of a collection) using (var XmlReader = new System.IO.StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.WonkaRegistry.init.xml"))) { string sInitRegistryXml = XmlReader.ReadToEnd(); // We deserialize/parse the contents of the config file System.Xml.Serialization.XmlSerializer WonkaEthSerializer = new System.Xml.Serialization.XmlSerializer(typeof(WonkaEth.Init.WonkaEthRegistryInitialization), new System.Xml.Serialization.XmlRootAttribute("WonkaEthRegistryInitialization")); moWonkaRegistryInit = WonkaEthSerializer.Deserialize(new System.IO.StringReader(sInitRegistryXml)) as WonkaEth.Init.WonkaEthRegistryInitialization; // Here, any embeddeded resources mentioned in the config file (instead of simple file URLs) are accessed here moWonkaRegistryInit.RetrieveEmbeddedResources(TmpAssembly); } // Here, we save all data from the config files to member properties // This region and the usage of member properties isn't necessary, but it's useful for debugging #region Set Class Member Variables msSenderAddress = moOrchInitData.BlockchainEngine.SenderAddress; msPassword = moOrchInitData.BlockchainEngine.Password; if (moOrchInitData.BlockchainEngine.ContractAddress == null) { msWonkaContractAddress = DeployWonkaContract(); } else { msWonkaContractAddress = moOrchInitData.BlockchainEngine.ContractAddress; } if (moOrchInitData.DefaultBlockchainDataSource.ContractAddress == null) { msOrchContractAddress = DeployOrchestrationContract(); } else { msOrchContractAddress = moOrchInitData.DefaultBlockchainDataSource.ContractAddress; } msAbiWonka = moOrchInitData.BlockchainEngine.ContractABI; msAbiOrchContract = moOrchInitData.DefaultBlockchainDataSource.ContractABI; moDefaultSource = new WonkaBreSource(moOrchInitData.DefaultBlockchainDataSource.SourceId, moOrchInitData.DefaultBlockchainDataSource.SenderAddress, moOrchInitData.DefaultBlockchainDataSource.Password, moOrchInitData.DefaultBlockchainDataSource.ContractAddress, moOrchInitData.DefaultBlockchainDataSource.ContractABI, moOrchInitData.DefaultBlockchainDataSource.MethodName, moOrchInitData.DefaultBlockchainDataSource.SetterMethodName, RetrieveValueMethod); foreach (WonkaRefAttr TempAttr in RefEnv.AttrCache) { moAttrSourceMap[TempAttr.AttrName] = moDefaultSource; } moCustomOpMap = moOrchInitData.BlockchainCustomOpFunctions; #endregion // We initialize the proxy that will be used to communicate with the Registry on the blockchain WonkaEth.Contracts.WonkaRuleTreeRegistry WonkaRegistry = WonkaEth.Contracts.WonkaRuleTreeRegistry.CreateInstance(moWonkaRegistryInit.BlockchainRegistry.ContractSender, moWonkaRegistryInit.BlockchainRegistry.ContractPassword, moWonkaRegistryInit.BlockchainRegistry.ContractAddress, moWonkaRegistryInit.BlockchainRegistry.ContractABI, moWonkaRegistryInit.Web3HttpUrl); // Here, the data domain is serialized to the blockchain for use by the RuleTree(s) RefEnv.Serialize(moOrchInitData.BlockchainEngineOwner, msPassword, msSenderAddress, msWonkaContractAddress, msAbiWonka, moOrchInitData.Web3HttpUrl); }
// This constructor will be called in the case that we wish to initialize the framework // with configuration files that will be accessed through IPFS public WonkaCQSOrchTest(StringBuilder psPeerKeyId, string psRulesMarkupFile, string psRulesInitFile, string psRegistryInitFile) { moAttrSourceMap = new Dictionary <string, WonkaBreSource>(); moCustomOpMap = new Dictionary <string, WonkaBreSource>(); var TmpAssembly = Assembly.GetExecutingAssembly(); WonkaRefEnvironment RefEnv = WonkaRefEnvironment.CreateInstance(false, moMetadataSource); WonkaIpfs.WonkaIpfsEnvironment IpfsEnv = WonkaIpfs.WonkaIpfsEnvironment.CreateInstance(); // Read the XML markup that lists the business rules msRulesContents = IpfsEnv.GetFile(psPeerKeyId.ToString(), psRulesMarkupFile); // Read the configuration file that contains all the initialization details regarding the rules engine // (like addresses of contracts, senders, passwords, etc.) string sInitXml = IpfsEnv.GetFile(psPeerKeyId.ToString(), psRulesInitFile); if (!String.IsNullOrEmpty(sInitXml)) { System.Xml.Serialization.XmlSerializer WonkaEthSerializer = new System.Xml.Serialization.XmlSerializer(typeof(WonkaEth.Init.WonkaEthInitialization), new System.Xml.Serialization.XmlRootAttribute("WonkaEthInitialization")); WonkaEth.Init.WonkaEthInitialization WonkaInit = WonkaEthSerializer.Deserialize(new System.IO.StringReader(sInitXml)) as WonkaEth.Init.WonkaEthInitialization; WonkaInit.RetrieveEmbeddedResources(TmpAssembly); moOrchInitData = WonkaInit.TransformIntoOrchestrationInit(moMetadataSource); System.Console.WriteLine("Number of custom operators: (" + WonkaInit.CustomOperatorList.Length + ")."); } // Read the configuration file that contains all the initialization details regarding the rules registry // (like Ruletree info, Grove info, etc.) string sInitRegistryXml = IpfsEnv.GetFile(psPeerKeyId.ToString(), psRegistryInitFile); if (!String.IsNullOrEmpty(sInitRegistryXml)) { System.Xml.Serialization.XmlSerializer WonkaEthSerializer = new System.Xml.Serialization.XmlSerializer(typeof(WonkaEth.Init.WonkaEthRegistryInitialization), new System.Xml.Serialization.XmlRootAttribute("WonkaEthRegistryInitialization")); moWonkaRegistryInit = WonkaEthSerializer.Deserialize(new System.IO.StringReader(sInitRegistryXml)) as WonkaEth.Init.WonkaEthRegistryInitialization; moWonkaRegistryInit.RetrieveEmbeddedResources(TmpAssembly); } #region Set Class Member Variables msSenderAddress = moOrchInitData.BlockchainEngine.SenderAddress; msPassword = moOrchInitData.BlockchainEngine.Password; if (moOrchInitData.BlockchainEngine.ContractAddress == null) { msWonkaContractAddress = DeployWonkaContract(); } else { msWonkaContractAddress = moOrchInitData.BlockchainEngine.ContractAddress; } if (moOrchInitData.DefaultBlockchainDataSource.ContractAddress == null) { msOrchContractAddress = DeployOrchestrationContract(); } else { msOrchContractAddress = moOrchInitData.DefaultBlockchainDataSource.ContractAddress; } msAbiWonka = moOrchInitData.BlockchainEngine.ContractABI; msAbiOrchContract = moOrchInitData.DefaultBlockchainDataSource.ContractABI; moDefaultSource = new WonkaBreSource(moOrchInitData.DefaultBlockchainDataSource.SourceId, moOrchInitData.DefaultBlockchainDataSource.SenderAddress, moOrchInitData.DefaultBlockchainDataSource.Password, moOrchInitData.DefaultBlockchainDataSource.ContractAddress, moOrchInitData.DefaultBlockchainDataSource.ContractABI, moOrchInitData.DefaultBlockchainDataSource.MethodName, moOrchInitData.DefaultBlockchainDataSource.SetterMethodName, RetrieveValueMethod); // Here a mapping is created, where each Attribute points to a specific contract and its "accessor" methods // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type foreach (WonkaRefAttr TempAttr in RefEnv.AttrCache) { moAttrSourceMap[TempAttr.AttrName] = moDefaultSource; } // Here a mapping is created, where each Custom Operator points to a specific contract and its "implementation" method // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type moCustomOpMap = moOrchInitData.BlockchainCustomOpFunctions; #endregion WonkaEth.Contracts.WonkaRuleTreeRegistry WonkaRegistry = WonkaEth.Contracts.WonkaRuleTreeRegistry.CreateInstance(moWonkaRegistryInit.BlockchainRegistry.ContractSender, moWonkaRegistryInit.BlockchainRegistry.ContractPassword, moWonkaRegistryInit.BlockchainRegistry.ContractAddress, moWonkaRegistryInit.BlockchainRegistry.ContractABI, moWonkaRegistryInit.Web3HttpUrl); RefEnv.Serialize(moOrchInitData.BlockchainEngineOwner, msPassword, msSenderAddress, msWonkaContractAddress, msAbiWonka, moOrchInitData.Web3HttpUrl); }
// This constructor will be called in the case that we wish to initialize the framework // with provided parameters public WonkaCQSOrchTest(string psSenderAddress, string psPassword, string psWonkaContractAddress, string psOrchContractAddress) { var TmpAssembly = Assembly.GetExecutingAssembly(); moAttrSourceMap = new Dictionary <string, WonkaBreSource>(); moCustomOpMap = new Dictionary <string, WonkaBreSource>(); // Read the ABI of the Ethereum contract for the Wonka rules engine using (var AbiReader = new StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.WonkaEngine.abi"))) { msAbiWonka = AbiReader.ReadToEnd(); } // Read the ABI of the Ethereum contract that will demonstrate both our Custom Operator functionality and our Orchestration functionality using (var AbiReader = new StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.OrchTest.abi"))) { msAbiOrchContract = AbiReader.ReadToEnd(); } // Read the XML markup that lists the business rules using (var RulesReader = new StreamReader(TmpAssembly.GetManifestResourceStream("WonkaSystem.TestData.VATCalculationExample.xml"))) { msRulesContents = RulesReader.ReadToEnd(); } // Using the metadata source, we create an instance of a defined data domain WonkaRefEnvironment RefEnv = WonkaRefEnvironment.CreateInstance(false, moMetadataSource); msSenderAddress = psSenderAddress; msPassword = psPassword; moMetadataSource = new WonkaMetadataTestSource(); if (psWonkaContractAddress == null) { msWonkaContractAddress = DeployWonkaContract(); } else { msWonkaContractAddress = psWonkaContractAddress; } if (psOrchContractAddress == null) { msOrchContractAddress = DeployOrchestrationContract(); } else { msOrchContractAddress = psOrchContractAddress; } // Serialize the data domain to the blockchain RefEnv.Serialize(msSenderAddress, msPassword, msSenderAddress, msWonkaContractAddress, msAbiWonka); moDefaultSource = new WonkaBreSource(CONST_ORCH_CONTRACT_MARKUP_ID, msSenderAddress, msPassword, psOrchContractAddress, msAbiOrchContract, CONST_ORCH_CONTRACT_GET_METHOD, CONST_ORCH_CONTRACT_SET_METHOD, RetrieveValueMethod); // Here a mapping is created, where each Attribute points to a specific contract and its "accessor" methods // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type foreach (WonkaRefAttr TempAttr in RefEnv.AttrCache) { moAttrSourceMap[TempAttr.AttrName] = moDefaultSource; } Dictionary <string, WonkaBreSource> CustomOpSourceMap = new Dictionary <string, WonkaBreSource>(); // Here a mapping is created, where each Custom Operator points to a specific contract and its "implementation" method // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type WonkaBreSource CustomOpSource = new WonkaBreSource(CONST_CUSTOM_OP_MARKUP_ID, msSenderAddress, msPassword, psOrchContractAddress, msAbiOrchContract, LookupVATDenominator, CONST_CUSTOM_OP_CONTRACT_METHOD); moCustomOpMap[CONST_CUSTOM_OP_MARKUP_ID] = CustomOpSource; }
/// <summary> /// /// This method will initialize an instance of the Wonka.Net engine, using all the data provided. /// /// <returns>None</returns> /// </summary> public static void InitEngine(this WonkaEthEngineInitialization poEngineInitData, bool pbRequireRetrieveValueMethod = true) { var EngineProps = poEngineInitData.Engine; if (EngineProps == null) { throw new Exception("ERROR! No engine properties provided."); } if ((EngineProps.RulesEngine == null) && !String.IsNullOrEmpty(EngineProps.RulesMarkupXml)) { if (pbRequireRetrieveValueMethod && (EngineProps.DotNetRetrieveMethod == null)) { throw new WonkaEthInitException("ERROR! Retrieve method not provided for the Wonka.NET engine.", poEngineInitData); } if (EngineProps.MetadataSource == null) { throw new WonkaEthInitException("ERROR! No metadata source has been provided.", poEngineInitData); } // Using the metadata source, we create an instance of a defined data domain WonkaRefEnvironment WonkaRefEnv = WonkaRefEnvironment.CreateInstance(false, EngineProps.MetadataSource); var account = new Account(poEngineInitData.EthPassword); Nethereum.Web3.Web3 web3 = null; if (!String.IsNullOrEmpty(poEngineInitData.Web3HttpUrl)) { web3 = new Nethereum.Web3.Web3(account, poEngineInitData.Web3HttpUrl); } else { web3 = new Nethereum.Web3.Web3(account); } if (String.IsNullOrEmpty(poEngineInitData.RulesEngineContractAddress)) { var EngineDeployment = new Autogen.WonkaEngine.WonkaEngineDeployment(); HexBigInteger nDeployGas = new HexBigInteger(CONST_DEPLOY_ENGINE_CONTRACT_GAS_COST); poEngineInitData.RulesEngineContractAddress = EngineDeployment.DeployContract(web3, poEngineInitData.RulesEngineABI, poEngineInitData.EthSenderAddress, nDeployGas, poEngineInitData.Web3HttpUrl); } if (String.IsNullOrEmpty(poEngineInitData.RegistryContractAddress)) { var RegistryDeployment = new Autogen.WonkaRegistry.WonkaRegistryDeployment(); HexBigInteger nDeployGas = new HexBigInteger(CONST_DEPLOY_DEFAULT_CONTRACT_GAS_COST); poEngineInitData.RegistryContractAddress = RegistryDeployment.DeployContract(web3, poEngineInitData.RegistryContractABI, poEngineInitData.EthSenderAddress, nDeployGas, poEngineInitData.Web3HttpUrl); } if (String.IsNullOrEmpty(poEngineInitData.StorageContractAddress)) { var TestContractDeployment = new Autogen.WonkaTestContract.WonkaTestContractDeployment(); HexBigInteger nDeployGas = new HexBigInteger(CONST_DEPLOY_DEFAULT_CONTRACT_GAS_COST); poEngineInitData.StorageContractAddress = TestContractDeployment.DeployContract(web3, poEngineInitData.StorageContractABI, poEngineInitData.EthSenderAddress, nDeployGas, poEngineInitData.Web3HttpUrl); } if ((EngineProps.SourceMap == null) || (EngineProps.SourceMap.Count == 0)) { EngineProps.SourceMap = new Dictionary <string, WonkaBre.RuleTree.WonkaBreSource>(); // Here a mapping is created, where each Attribute points to a specific contract and its "accessor" methods // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type foreach (WonkaRefAttr TempAttr in WonkaRefEnv.AttrCache) { WonkaBreSource TempSource = new WonkaBreSource(poEngineInitData.StorageDefaultSourceId, poEngineInitData.EthSenderAddress, poEngineInitData.EthPassword, poEngineInitData.StorageContractAddress, poEngineInitData.StorageContractABI, poEngineInitData.StorageGetterMethod, poEngineInitData.StorageSetterMethod, EngineProps.DotNetRetrieveMethod); EngineProps.SourceMap[TempAttr.AttrName] = TempSource; } } EngineProps.RulesEngine = new WonkaBreRulesEngine(new StringBuilder(EngineProps.RulesMarkupXml), EngineProps.SourceMap, EngineProps.MetadataSource); EngineProps.RulesEngine.DefaultSource = poEngineInitData.StorageDefaultSourceId; EngineProps.RulesEngine.SetDefaultStdOps(poEngineInitData.EthPassword, poEngineInitData.Web3HttpUrl); } }
public RuleTreeReport ExecuteWithReport(WonkaBreRulesEngine poRulesEngine, bool pbValidateWithinTransaction, WonkaBreSource poSource, string psOrchestrationAddress) { WonkaRefEnvironment RefEnv = WonkaRefEnvironment.GetInstance(); WonkaRefAttr NewSellTaxAmountAttr = RefEnv.GetAttributeByAttrName("NewSellTaxAmount"); WonkaRefAttr NewVATAmountForHMRCAttr = RefEnv.GetAttributeByAttrName("NewVATAmountForHMRC"); WonkaRefAttr NewSalesTransSeqAttr = RefEnv.GetAttributeByAttrName("NewSalesTransSeq"); WonkaRefAttr NewSaleVATRateDenomAttr = RefEnv.GetAttributeByAttrName("NewSaleVATRateDenom"); WonkaRefAttr PrevSellTaxAmtAttr = RefEnv.GetAttributeByAttrName("PrevSellTaxAmount"); WonkaRefAttr NewSaleItemTypeAttr = RefEnv.GetAttributeByAttrName("NewSaleItemType"); WonkaRefAttr CountryOfSaleAttr = RefEnv.GetAttributeByAttrName("CountryOfSale"); bool bTestLookupMethod = true; Dictionary <string, string> PrdKeys = new Dictionary <string, string>(); var contract = GetContract(); var executeWithReportFunction = contract.GetFunction(CONST_CONTRACT_FUNCTION_EXEC_RPT); RuleTreeReport ruleTreeReport = null; if (bTestLookupMethod) { var contractOrchTest = GetContractOrchTest(psOrchestrationAddress); var gas = new Nethereum.Hex.HexTypes.HexBigInteger(1000000); var executeLookupFunction = contractOrchTest.GetFunction("lookupVATDenominator"); var lookupValue = executeLookupFunction.CallAsync <string>("Widget", "UK", "", "").Result; var getValOnRecordFunction = contract.GetFunction("getValueOnRecord"); var attrVal = getValOnRecordFunction.CallAsync <string>(poSource.SenderAddress, "NewSaleItemType").Result; } if (pbValidateWithinTransaction) { var executeGetLastReportFunction = contract.GetFunction(CONST_CONTRACT_FUNCTION_GET_LAST_RPT); // NOTE: Caused exception to be thrown // var gas = executeWithReportFunction.EstimateGasAsync(msSenderAddress).Result; var gas = new Nethereum.Hex.HexTypes.HexBigInteger(2000000); WonkaProduct OrchContractCurrValues = poRulesEngine.AssembleCurrentProduct(new Dictionary <string, string>()); string sNSTABeforeOrchestrationAssignment = RetrieveValueMethod(poSource, NewSellTaxAmountAttr.AttrName); string sNVABeforeOrchestrationAssignment = RetrieveValueMethod(poSource, NewVATAmountForHMRCAttr.AttrName); string sNSTSBeforeOrchestrationAssignment = RetrieveValueMethod(poSource, NewSalesTransSeqAttr.AttrName); string sNSVRDBeforeOrchestrationAssignment = RetrieveValueMethod(poSource, NewSaleVATRateDenomAttr.AttrName); string sPSTABeforeOrchestrationAssignment = RetrieveValueMethod(poSource, PrevSellTaxAmtAttr.AttrName); string sNSITDBeforeOrchestrationAssignment = RetrieveValueMethod(poSource, NewSaleItemTypeAttr.AttrName); string sCoSBeforeOrchestrationAssignment = RetrieveValueMethod(poSource, CountryOfSaleAttr.AttrName); var receiptAddAttribute = executeWithReportFunction.SendTransactionAsync(msSenderAddress, gas, null, msSenderAddress).Result; string sNSTAfterOrchestrationAssignment = RetrieveValueMethod(poSource, NewSellTaxAmountAttr.AttrName); string sNVAAfterOrchestrationAssignment = RetrieveValueMethod(poSource, NewVATAmountForHMRCAttr.AttrName); string sNSTSAfterOrchestrationAssignment = RetrieveValueMethod(poSource, NewSalesTransSeqAttr.AttrName); string sNSVRDAfterOrchestrationAssignment = RetrieveValueMethod(poSource, NewSaleVATRateDenomAttr.AttrName); string sPSTAAfterOrchestrationAssignment = RetrieveValueMethod(poSource, PrevSellTaxAmtAttr.AttrName); string sNSITDAfterOrchestrationAssignment = RetrieveValueMethod(poSource, NewSaleItemTypeAttr.AttrName); string sCoSAfterOrchestrationAssignment = RetrieveValueMethod(poSource, CountryOfSaleAttr.AttrName); ruleTreeReport = executeGetLastReportFunction.CallDeserializingToObjectAsync <RuleTreeReport>().Result; } else { ruleTreeReport = executeWithReportFunction.CallDeserializingToObjectAsync <RuleTreeReport>(msSenderAddress).Result; } return(ruleTreeReport); }
public void Execute(string psOrchestrationTestAddress = null, bool pbValidateWithinTransaction = false) { WonkaRefEnvironment RefEnv = WonkaRefEnvironment.GetInstance(); Dictionary <string, WonkaBre.RuleTree.WonkaBreSource> SourceMap = new Dictionary <string, WonkaBre.RuleTree.WonkaBreSource>(); string sDefaultSourceId = "S"; string sContractSourceId = sDefaultSourceId; string sContractAddress = ""; string sContractAbi = ""; string sOrchGetterMethod = ""; string sOrchSetterMethod = ""; // These values indicate the Custom Operator "INVOKE_VAT_LOOKUP" which has been used in the markup - // its implementation can be found in the method "lookupVATDenominator" string sCustomOpId = "INVOKE_VAT_LOOKUP"; string sCustomOpMethod = "lookupVATDenominator"; // If a 'psOrchestrationTestAddress' value has been provided, it indicates that the user wishes // to use Orchestration if (!String.IsNullOrEmpty(psOrchestrationTestAddress)) { sContractAddress = psOrchestrationTestAddress; sContractAbi = msAbiOrchTest; sOrchGetterMethod = "getAttrValueBytes32"; sOrchSetterMethod = "setAttrValueBytes32"; } else { sContractAddress = msContractAddress; sContractAbi = msAbiWonka; sOrchGetterMethod = "getValueOnRecord"; sOrchSetterMethod = ""; } WonkaBreSource DefaultSource = new WonkaBreSource(sContractSourceId, msSenderAddress, msPassword, sContractAddress, sContractAbi, sOrchGetterMethod, sOrchSetterMethod, RetrieveValueMethod); // Here a mapping is created, where each Attribute points to a specific contract and its "accessor" methods // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type foreach (WonkaRefAttr TempAttr in moTargetAttrList) { SourceMap[TempAttr.AttrName] = DefaultSource; } Dictionary <string, WonkaBreSource> CustomOpSourceMap = new Dictionary <string, WonkaBreSource>(); // Here a mapping is created, where each Custom Operator points to a specific contract and its "implementation" method // - the class that contains this information (contract, accessors, etc.) is of the WonkaBreSource type WonkaBreSource CustomOpSource = new WonkaBreSource(sCustomOpId, msSenderAddress, msPassword, sContractAddress, sContractAbi, LookupVATDenominator, sCustomOpMethod); CustomOpSourceMap[sCustomOpId] = CustomOpSource; // Creating an instance of the rules engine using our rules and the metadata WonkaBreRulesEngine RulesEngine = new WonkaBreRulesEngine(new StringBuilder(msRulesContents), SourceMap, CustomOpSourceMap, moMetadataSource, false); RulesEngine.DefaultSource = sDefaultSourceId; // The contract dictates that the RuleTree (and its other info, like the Orchestration and CU metadata) // is serialized to the blockchain before interacting with it SerializeRulesEngineToBlockchain(RulesEngine); WonkaRefAttr NewSellTaxAmountAttr = RefEnv.GetAttributeByAttrName("NewSellTaxAmount"); WonkaRefAttr NewVATAmountForHMRCAttr = RefEnv.GetAttributeByAttrName("NewVATAmountForHMRC"); // Gets a predefined data record that will be our analog for new data coming into the system // We are only using this record to test the .NET implementation WonkaProduct NewProduct = GetNewProduct(); string sSellAmtBefore = GetAttributeValue(NewProduct, NewSellTaxAmountAttr); string sVATAmtBefore = GetAttributeValue(NewProduct, NewVATAmountForHMRCAttr); /** ** Test the .NET side */ WonkaBre.Reporting.WonkaBreRuleTreeReport Report = RulesEngine.Validate(NewProduct); string sSellAmtAfter = GetAttributeValue(NewProduct, NewSellTaxAmountAttr); string sVATAmtAfter = GetAttributeValue(NewProduct, NewVATAmountForHMRCAttr); if (Report.OverallRuleTreeResult == ERR_CD.CD_SUCCESS) { // NOTE: This should only be used for further testing // Serialize(NewProduct); } else if (Report.GetRuleSetFailureCount() > 0) { System.Console.WriteLine(".NET Engine says \"Oh heavens to Betsy! Something bad happened!\""); } else { System.Console.WriteLine(".NET Engine says \"What in the world is happening?\""); } // If a 'psOrchestrationTestAddress' value has been provided, it indicates that the user wishes // to use Orchestration if (!String.IsNullOrEmpty(psOrchestrationTestAddress)) { /** ** Now execute the rules engine on the blockchain, using both Orchestration to call accessors ** on other contract(s) and Custom Operators to invoke the "INVOKE_VAT_LOOKUP" operator ** (i.e., the "lookupVATDenominator()" method) implemented on a contract. ** ** NOTE: Based on the value of the argument 'pbValidateWithinTransaction', we will act accordingly - ** If set to 'true', we issue a call() when we execute the rules engine, since we are only ** looking to validate here. However, if the value if 'false', we issue a sendTransaction() ** so that we can attempts to set values (i.e., change the blockchain) will take effect. ** In that case, we might want to pull back the record afterwards with a subsequent function ** call, in order to examine the record here. ** **/ var BlockchainReport = ExecuteWithReport(RulesEngine, pbValidateWithinTransaction, SourceMap[NewSellTaxAmountAttr.AttrName], psOrchestrationTestAddress); if (BlockchainReport.NumberOfRuleFailures == 0) { // Indication of a success } else if (BlockchainReport.NumberOfRuleFailures > 0) { throw new Exception("Oh heavens to Betsy! Something bad happened!"); } else { throw new Exception("Seriously, what in the world is happening?!"); } } }