Example #1
0
        /// <summary>
        /// //TODO: in fact, only public interface of contact need to be added into FunctionMetadataMap
        /// </summary>
        /// <param name="chainId"></param>
        /// <param name="contractAddr"></param>
        /// <param name="contractMetadataTemplate"></param>
        /// <exception cref="FunctionMetadataException"></exception>
        public async Task DeployNewContract(Hash chainId, Address contractAddr, ContractMetadataTemplate contractMetadataTemplate)
        {
            Dictionary <string, FunctionMetadata> tempMap = new Dictionary <string, FunctionMetadata>();

            try
            {
                var globalCallGraph = await GetCallingGraphForChain(chainId);

                var newCallGraph = TryUpdateAndGetCallingGraph(chainId, contractAddr, globalCallGraph, contractMetadataTemplate);

                foreach (var localFuncName in contractMetadataTemplate.ProcessFunctionOrder)
                {
                    var funcNameWithAddr =
                        Replacement.ReplaceValueIntoReplacement(localFuncName, Replacement.This,
                                                                contractAddr.DumpHex());
                    var funcMetadata = await GetMetadataForNewFunction(chainId, funcNameWithAddr,
                                                                       contractMetadataTemplate.MethodMetadataTemplates[localFuncName],
                                                                       contractAddr, contractMetadataTemplate.ContractReferences, tempMap);

                    tempMap.Add(funcNameWithAddr, funcMetadata);
                }

                //if no exception is thrown, merge the tempMap into FunctionMetadataMap and update call graph in database
                await _dataStore.InsertAsync(chainId.OfType(HashType.CallingGraph),
                                             SerializeCallingGraph(newCallGraph));

                foreach (var functionMetadata in tempMap)
                {
                    FunctionMetadataMap.Add(functionMetadata.Key, functionMetadata.Value);

                    await _dataStore.InsertAsync(
                        DataPath.CalculatePointerForMetadata(chainId, functionMetadata.Key),
                        functionMetadata.Value);
                }
            }
            catch (FunctionMetadataException e)
            {
                _logger?.Error(e, "Exception while deploy new contract.");
                throw;
            }
        }
Example #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="chainId"></param>
        /// <param name="functionFullName"></param>
        /// <returns></returns>
        /// <exception cref="InvalidParameterException"></exception>
        public async Task <FunctionMetadata> GetFunctionMetadata(Hash chainId, string functionFullName)
        {
            //BUG: if the smart contract can be updated, then somehow this in-memory cache FunctionMetadataMap need to be updated too. Currently the ChainFunctionMetadata has no way to know some metadata is updated; current thought is to request current "previous block hash" every time the ChainFunctionMetadata public interface got executed, that is "only use cache when in the same block, can clear the cache per block"
            if (!FunctionMetadataMap.TryGetValue(functionFullName, out var txMetadata))
            {
                var data = await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, functionFullName));

                if (data != null)
                {
                    txMetadata = data;
                    FunctionMetadataMap.Add(functionFullName, txMetadata);
                }
                else
                {
                    throw new InvalidParameterException("There are no function named " + functionFullName +
                                                        " in the FunctionMetadataMap");
                }
            }

            return(txMetadata);
        }
        public async Task TestDepolyContract()
        {
            var chainId       = Hash.Generate();
            var runner        = _smartContractRunnerFactory.GetRunner(0);
            var contractCType = typeof(TestContractC);
            var contractBType = typeof(TestContractB);
            var contractAType = typeof(TestContractA);

            var contractCTemplate = runner.ExtractMetadata(contractCType);
            var contractBTemplate = runner.ExtractMetadata(contractBType);
            var contractATemplate = runner.ExtractMetadata(contractAType);

            var addrA = Address.FromString("TestContractA");
            var addrB = Address.FromString("TestContractB");
            var addrC = Address.FromString("TestContractC");

            Console.WriteLine(addrC);

            await _functionMetadataService.DeployContract(chainId, addrC, contractCTemplate);

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrC.DumpHex() + ".Func0")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrC.DumpHex() + ".Func1")));

            await _functionMetadataService.DeployContract(chainId, addrB, contractBTemplate);

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrC.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrB.DumpHex() + ".Func0")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource3", DataAccessMode.ReadOnlyAccountSharing),
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrB.DumpHex() + ".Func1")));

            await _functionMetadataService.DeployContract(chainId, addrA, contractATemplate);

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>()), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func0(int)")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func0")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func2"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func1")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func0",
                addrB.DumpHex() + ".Func0",
                addrC.DumpHex() + ".Func0"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func3")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func2"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func4")));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func3",
                addrB.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource3", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func5")));

            var callGraph = new SerializedCallGraph
            {
                Vertices =
                {
                    addrC.DumpHex() + ".Func0",
                    addrC.DumpHex() + ".Func1",
                    addrB.DumpHex() + ".Func0",
                    addrB.DumpHex() + ".Func1",
                    addrA.DumpHex() + ".Func0(int)",
                    addrA.DumpHex() + ".Func0",
                    addrA.DumpHex() + ".Func1",
                    addrA.DumpHex() + ".Func2",
                    addrA.DumpHex() + ".Func3",
                    addrA.DumpHex() + ".Func4",
                    addrA.DumpHex() + ".Func5"
                },
                Edges =
                {
                    new GraphEdge
                    {
                        Source = addrB.DumpHex() + ".Func0",
                        Target = addrC.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func0",
                        Target = addrA.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func1",
                        Target = addrA.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrB.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrA.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrC.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func4",
                        Target = addrA.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func5",
                        Target = addrB.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func5",
                        Target = addrA.DumpHex() + ".Func3"
                    }
                }
            };

            Assert.Equal(callGraph, await _dataStore.GetAsync <SerializedCallGraph>(chainId.OfType(HashType.CallingGraph)));
        }
        public async Task TestEmptyContract()
        {
            var chainId                = Hash.Generate();
            var runner                 = _smartContractRunnerFactory.GetRunner(0);
            var contractCType          = typeof(TestContractC);
            var contractBType          = typeof(TestContractB);
            var contractAType          = typeof(TestContractA);
            var nonAttrContract1Type   = typeof(TestNonAttrContract1);
            var nonAttrContract2Type   = typeof(TestNonAttrContract2);
            var refNonAttrContractType = typeof(TestRefNonAttrContract);

            var contractCTemplate          = runner.ExtractMetadata(contractCType);
            var contractBTemplate          = runner.ExtractMetadata(contractBType);
            var contractATemplate          = runner.ExtractMetadata(contractAType);
            var nonAttrContract1Template   = runner.ExtractMetadata(nonAttrContract1Type);
            var nonAttrContract2Template   = runner.ExtractMetadata(nonAttrContract2Type);
            var refNonAttrContractTemplate = runner.ExtractMetadata(refNonAttrContractType);


            var contract1Addr   = Address.FromString("TestNonAttrContract1");   // 0x3f77405cbfe1e48e2fa0e4bf6a4e5917f768
            var contract2Addr   = Address.FromString("TestNonAttrContract2");   // 0xb4e0cc36ede5d518fbabd1ed5498093e4b71
            var refContractAddr = Address.FromString("TestRefNonAttrContract"); // 0x7c7f78ecc9f78be2a502e5bf9f22112c6a47

            var addrA = Address.FromString("TestContractA");                    // 0x46c86551bca0e3120ca0f831f53d8cb55ac7
            var addrB = Address.FromString("TestContractB");                    // 0xea0e38633e550dc4b7914010c2d7c95086ee
            var addrC = Address.FromString("TestContractC");                    // 0x053f751c35f7c681be14bcee03085dc8a309

            await _functionMetadataService.DeployContract(chainId, addrC, contractCTemplate);

            await _functionMetadataService.DeployContract(chainId, addrB, contractBTemplate);

            await _functionMetadataService.DeployContract(chainId, addrA, contractATemplate);

            await _functionMetadataService.DeployContract(chainId, contract1Addr, nonAttrContract1Template);

            await _functionMetadataService.DeployContract(chainId, contract2Addr, nonAttrContract2Template);

            await _functionMetadataService.DeployContract(chainId, refContractAddr, refNonAttrContractTemplate);

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrC.DumpHex() + ".Func0"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrC.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrC.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrB.DumpHex() + ".Func0"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource3", DataAccessMode.ReadOnlyAccountSharing),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrB.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>()), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func0(int)"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func0"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func2"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func0",
                addrB.DumpHex() + ".Func0",
                addrC.DumpHex() + ".Func0"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func3"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func2"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func4"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                addrA.DumpHex() + ".Func3",
                addrB.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new[]
            {
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource0", DataAccessMode.AccountSpecific),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource3", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrB.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.AccountSpecific),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource5", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource1", DataAccessMode.ReadOnlyAccountSharing),
                new Resource(addrA.Value.ToByteArray().ToHex() + ".resource2", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, addrA.DumpHex() + ".Func5"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, contract1Addr.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, contract1Addr.DumpHex() + ".Func2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(contract2Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, contract2Addr.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(),
                             new HashSet <Resource>(new []
            {
                new Resource(contract2Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, contract2Addr.DumpHex() + ".Func2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new [] { contract1Addr.DumpHex() + ".Func1" }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new [] { contract1Addr.DumpHex() + ".Func1" }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
                new Resource(refContractAddr.Value.ToByteArray().ToHex() + ".localRes", DataAccessMode.AccountSpecific)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func1_1"))));
            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new [] { contract1Addr.DumpHex() + ".Func2" }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                contract1Addr.DumpHex() + ".Func2",
                refContractAddr.DumpHex() + ".Func1_1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
                new Resource(refContractAddr.Value.ToByteArray().ToHex() + ".localRes", DataAccessMode.AccountSpecific)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func2_1"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                contract1Addr.DumpHex() + ".Func2",
                refContractAddr.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func2_2"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                contract1Addr.DumpHex() + ".Func1",
                contract1Addr.DumpHex() + ".Func2"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func3"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                contract1Addr.DumpHex() + ".Func1",
                contract2Addr.DumpHex() + ".Func1"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
                new Resource(contract2Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing)
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func4"))));

            Assert.Equal(new FunctionMetadata(
                             new HashSet <string>(new []
            {
                contract1Addr.DumpHex() + ".Func2",
                addrC.DumpHex() + ".Func0"
            }),
                             new HashSet <Resource>(new []
            {
                new Resource(contract1Addr.Value.ToByteArray().ToHex() + "._lock", DataAccessMode.ReadWriteAccountSharing),
                new Resource(addrC.Value.ToByteArray().ToHex() + ".resource4", DataAccessMode.AccountSpecific),
            })), (await _dataStore.GetAsync <FunctionMetadata>(DataPath.CalculatePointerForMetadata(chainId, refContractAddr.DumpHex() + ".Func5"))));

            var callGraph = new SerializedCallGraph
            {
                Vertices =
                {
                    addrC.DumpHex() + ".Func0",
                    addrC.DumpHex() + ".Func1",
                    addrB.DumpHex() + ".Func0",
                    addrB.DumpHex() + ".Func1",
                    addrA.DumpHex() + ".Func0(int)",
                    addrA.DumpHex() + ".Func0",
                    addrA.DumpHex() + ".Func1",
                    addrA.DumpHex() + ".Func2",
                    addrA.DumpHex() + ".Func3",
                    addrA.DumpHex() + ".Func4",
                    addrA.DumpHex() + ".Func5",

                    contract1Addr.DumpHex() + ".Func1",
                    contract1Addr.DumpHex() + ".Func2",
                    contract2Addr.DumpHex() + ".Func1",
                    contract2Addr.DumpHex() + ".Func2",
                    refContractAddr.DumpHex() + ".Func1",
                    refContractAddr.DumpHex() + ".Func1_1",
                    refContractAddr.DumpHex() + ".Func2",
                    refContractAddr.DumpHex() + ".Func2_1",
                    refContractAddr.DumpHex() + ".Func2_2",
                    refContractAddr.DumpHex() + ".Func3",
                    refContractAddr.DumpHex() + ".Func4",
                    refContractAddr.DumpHex() + ".Func5"
                },
                Edges =
                {
                    new GraphEdge
                    {
                        Source = addrB.DumpHex() + ".Func0",
                        Target = addrC.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func0",
                        Target = addrA.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func1",
                        Target = addrA.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrB.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrA.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func3",
                        Target = addrC.DumpHex() + ".Func0"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func4",
                        Target = addrA.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func5",
                        Target = addrB.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = addrA.DumpHex() + ".Func5",
                        Target = addrA.DumpHex() + ".Func3"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func1",
                        Target = contract1Addr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func1_1",
                        Target = contract1Addr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func2",
                        Target = contract1Addr.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func2_1",
                        Target = contract1Addr.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func2_1",
                        Target = refContractAddr.DumpHex() + ".Func1_1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func2_2",
                        Target = contract1Addr.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func2_2",
                        Target = refContractAddr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func3",
                        Target = contract1Addr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func3",
                        Target = contract1Addr.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func4",
                        Target = contract1Addr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func4",
                        Target = contract2Addr.DumpHex() + ".Func1"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func5",
                        Target = contract1Addr.DumpHex() + ".Func2"
                    },
                    new GraphEdge
                    {
                        Source = refContractAddr.DumpHex() + ".Func5",
                        Target = addrC.DumpHex() + ".Func0"
                    }
                }
            };

            Assert.Equal(callGraph, await _dataStore.GetAsync <SerializedCallGraph>(chainId.OfType(HashType.CallingGraph)));
        }