public void SmartContractList_ListHasValueTest() { var listName = "testList"; var source = new MemoryDictionarySource(); var root = new ContractStateRoot(source); IContractState state = root.StartTracking(); IPersistenceStrategy persistenceStrategy = new PersistenceStrategy(state); var persistentState = new PersistentState( persistenceStrategy, this.contractPrimitiveSerializer, uint160.One); var list = new SmartContractList <string>(persistentState, listName); Assert.Equal((uint)0, list.Count); var testItem = "Test"; list.Add(testItem); var item1 = list.GetValue(0); Assert.Equal(testItem, item1); }
public void Repository_CommitAndRollbackTest() { ISource <byte[], byte[]> stateDB = new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()); ContractStateRoot repository = new ContractStateRoot(stateDB); IContractState txTrack = repository.StartTracking(); txTrack.CreateAccount(testAddress); txTrack.SetStorageValue(testAddress, dog, cat); txTrack.Commit(); repository.Commit(); byte[] root1 = repository.Root; IContractState txTrack2 = repository.StartTracking(); txTrack2.SetStorageValue(testAddress, dog, fish); txTrack2.Rollback(); IContractState txTrack3 = repository.StartTracking(); txTrack3.SetStorageValue(testAddress, dodecahedron, bird); txTrack3.Commit(); repository.Commit(); byte[] upToDateRoot = repository.Root; Assert.Equal(cat, repository.GetStorageValue(testAddress, dog)); Assert.Equal(bird, repository.GetStorageValue(testAddress, dodecahedron)); IContractState snapshot = repository.GetSnapshotTo(root1); repository.SyncToRoot(root1); Assert.Equal(cat, snapshot.GetStorageValue(testAddress, dog)); Assert.Null(snapshot.GetStorageValue(testAddress, dodecahedron)); }
/// <summary> /// Initialize a smart contract executor for the block assembler or consensus validator. /// <para> /// After the contract has been executed, it will process any fees and/or refunds. /// </para> /// </summary> public ISmartContractExecutor CreateExecutor( IContractState stateRepository, ISmartContractTransactionContext transactionContext) { return(new Executor(this.loggerFactory, this.contractPrimitiveSerializer, this.serializer, stateRepository, this.refundProcessor, this.transferProcessor, this.vm)); }
public void SmartContractList_CanAccessValueUsingIndexTest() { var listName = "testList"; var source = new MemoryDictionarySource(); var root = new ContractStateRoot(source); IContractState state = root.StartTracking(); IPersistenceStrategy persistenceStrategy = new PersistenceStrategy(state); var persistentState = new PersistentState( persistenceStrategy, this.contractPrimitiveSerializer, uint160.One); var list = new SmartContractList <string>(persistentState, listName); Assert.Equal((uint)0, list.Count); // Set a value in the list list.Add("Test"); list.Add("Test2"); var testItem = list.GetValue(0); var testItem2 = list.GetValue(1); var firstItemHash = $"{listName}[0]"; var secondItemHash = $"{listName}[1]"; var item = persistentState.GetString(firstItemHash); var item2 = persistentState.GetString(secondItemHash); Assert.Equal(testItem, item); Assert.Equal(testItem2, item2); }
public MeteredPersistenceStrategy(IContractState stateDb, IGasMeter gasMeter, IKeyEncodingStrategy keyEncodingStrategy) { Guard.NotNull(stateDb, nameof(stateDb)); Guard.NotNull(gasMeter, nameof(gasMeter)); Guard.NotNull(gasMeter, nameof(keyEncodingStrategy)); this.stateDb = stateDb; this.gasMeter = gasMeter; this.keyEncodingStrategy = keyEncodingStrategy; }
public void Test20DBreeze() { DBreezeEngine engine = new DBreezeEngine(DbreezeTestLocation); using (DBreeze.Transactions.Transaction t = engine.GetTransaction()) { t.RemoveAllKeys(DbreezeTestDb, true); t.Commit(); } ISource <byte[], byte[]> stateDB = new NoDeleteSource <byte[], byte[]>(new DBreezeByteStore(engine, DbreezeTestDb)); ContractStateRoot repository = new ContractStateRoot(stateDB); byte[] root = repository.Root; uint160 cowAddress = new uint160(cow); uint160 horseAddress = new uint160(horse); IContractState track2 = repository.StartTracking(); //repository track2.SetStorageValue(cowAddress, cowKey1, cowVal1); track2.SetStorageValue(horseAddress, horseKey1, horseVal1); track2.Commit(); repository.Commit(); byte[] root2 = repository.Root; track2 = repository.StartTracking(); //repository track2.SetStorageValue(cowAddress, cowKey2, cowVal0); track2.SetStorageValue(horseAddress, horseKey2, horseVal0); track2.Commit(); repository.Commit(); byte[] root3 = repository.Root; IContractState snapshot = new ContractStateRoot(stateDB, root); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey2)); snapshot = new ContractStateRoot(stateDB, root2); Assert.Equal(cowVal1, snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Equal(horseVal1, snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey2)); snapshot = new ContractStateRoot(stateDB, root3); Assert.Equal(cowVal1, snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Equal(cowVal0, snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Equal(horseVal1, snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Equal(horseVal0, snapshot.GetStorageValue(horseAddress, horseKey2)); }
public TransactionCondenser(uint160 contractAddress, ILoggerFactory loggerFactory, IReadOnlyList <TransferInfo> transfers, IContractState stateRepository, Network network, ISmartContractTransactionContext transactionContext) { this.contractAddress = contractAddress; this.logger = loggerFactory.CreateLogger(this.GetType().Name); this.network = network; this.transactionContext = transactionContext; this.stateRepository = stateRepository; this.transfers = transfers; this.nVouts = new Dictionary <uint160, uint>(); this.txBalances = new Dictionary <uint160, ulong>(); this.unspents = new List <ContractUnspentOutput>(); }
public void Repository_CommitPushesToUnderlyingSource() { ISource <byte[], byte[]> stateDB = new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()); ContractStateRoot repository = new ContractStateRoot(stateDB); IContractState txTrack = repository.StartTracking(); txTrack.CreateAccount(testAddress); txTrack.SetStorageValue(testAddress, dog, cat); Assert.Null(repository.GetStorageValue(testAddress, dog)); txTrack.Commit(); Assert.Equal(cat, repository.GetStorageValue(testAddress, dog)); }
public void Test4() { MemoryDictionarySource source = new MemoryDictionarySource(); ContractStateRoot root = new ContractStateRoot(source); IContractState repository = root.StartTracking(); repository.SetStorageValue(new uint160(cow), cowKey, cowValue); repository.SetStorageValue(new uint160(horse), horseKey, horseValue); repository.Commit(); Assert.Equal(cowValue, root.GetStorageValue(new uint160(cow), cowKey)); Assert.Equal(horseValue, root.GetStorageValue(new uint160(horse), horseKey)); }
/// <summary> /// Reverts the state to a previous snapshot. /// </summary> private void Rollback(StateSnapshot snapshot) { this.intermediateState = snapshot.ContractState; // Reset the nonce this.Nonce = snapshot.Nonce; // Rollback internal transfers this.internalTransfers.Clear(); this.internalTransfers.AddRange(snapshot.InternalTransfers); // Rollback logs this.LogHolder.Clear(); this.LogHolder.AddRawLogs(snapshot.Logs); }
private StateTransitionResult ApplyCall(CallMessage message, byte[] contractCode) { if (this.GasRemaining < message.GasLimit || this.GasRemaining < GasPriceList.BaseCost) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientGas)); } var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); if (message.Method.Name == null) { return(StateTransitionResult.Fail(gasMeter.GasConsumed, StateTransitionErrorKind.NoMethodName)); } StateSnapshot stateSnapshot = this.TakeSnapshot(); IContractState state = this.CreateIntermediateState(); string type = state.GetContractType(message.To); ISmartContractState smartContractState = this.CreateSmartContractState(gasMeter, message.To, message, state); VmExecutionResult result = this.Vm.ExecuteMethod(smartContractState, message.Method, contractCode, type); this.GasRemaining -= gasMeter.GasConsumed; bool revert = result.ExecutionException != null; if (revert) { this.Rollback(stateSnapshot); return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.ExecutionException)); } state.Commit(); this.GasRemaining -= gasMeter.GasConsumed; return(StateTransitionResult.Ok( gasMeter.GasConsumed, message.To, result.Result )); }
public Executor(ILoggerFactory loggerFactory, IContractPrimitiveSerializer contractPrimitiveSerializer, ICallDataSerializer serializer, IContractState stateSnapshot, ISmartContractResultRefundProcessor refundProcessor, ISmartContractResultTransferProcessor transferProcessor, ISmartContractVirtualMachine vm) { this.logger = loggerFactory.CreateLogger(this.GetType()); this.contractPrimitiveSerializer = contractPrimitiveSerializer; this.stateSnapshot = stateSnapshot; this.refundProcessor = refundProcessor; this.transferProcessor = transferProcessor; this.vm = vm; this.serializer = serializer; }
public void Test12() { ContractStateRoot repository = new ContractStateRoot(new MemoryDictionarySource()); IContractState track = repository.StartTracking(); track.SetCode(new uint160(cow), cowCode); track.SetCode(new uint160(horse), horseCode); Assert.Equal(cowCode, track.GetCode(new uint160(cow))); Assert.Equal(horseCode, track.GetCode(new uint160(horse))); track.Rollback(); Assert.Null(repository.GetCode(new uint160(cow))); Assert.Null(repository.GetCode(new uint160(horse))); }
public void Test20() { ISource <byte[], byte[]> stateDB = new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()); ContractStateRoot repository = new ContractStateRoot(stateDB); byte[] root = repository.Root; uint160 cowAddress = new uint160(cow); uint160 horseAddress = new uint160(horse); IContractState track2 = repository.StartTracking(); //repository track2.SetStorageValue(cowAddress, cowKey1, cowVal1); track2.SetStorageValue(horseAddress, horseKey1, horseVal1); track2.Commit(); repository.Commit(); byte[] root2 = repository.Root; track2 = repository.StartTracking(); //repository track2.SetStorageValue(cowAddress, cowKey2, cowVal0); track2.SetStorageValue(horseAddress, horseKey2, horseVal0); track2.Commit(); repository.Commit(); byte[] root3 = repository.Root; IContractState snapshot = new ContractStateRoot(stateDB, root); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey2)); snapshot = new ContractStateRoot(stateDB, root2); Assert.Equal(cowVal1, snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Null(snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Equal(horseVal1, snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Null(snapshot.GetStorageValue(horseAddress, horseKey2)); snapshot = new ContractStateRoot(stateDB, root3); Assert.Equal(cowVal1, snapshot.GetStorageValue(cowAddress, cowKey1)); Assert.Equal(cowVal0, snapshot.GetStorageValue(cowAddress, cowKey2)); Assert.Equal(horseVal1, snapshot.GetStorageValue(horseAddress, horseKey1)); Assert.Equal(horseVal0, snapshot.GetStorageValue(horseAddress, horseKey2)); }
public IInternalTransactionExecutor Create(ISmartContractVirtualMachine vm, IContractLogHolder contractLogHolder, IContractState stateRepository, List <TransferInfo> internalTransferList, ITransactionContext transactionContext) { return(new InternalTransactionExecutor( transactionContext, vm, contractLogHolder, stateRepository, internalTransferList, this.keyEncodingStrategy, this.loggerFactory, this.network )); }
private StateTransitionResult ApplyCreate(object[] parameters, byte[] code, BaseMessage message, string type = null) { if (this.GasRemaining < message.GasLimit || this.GasRemaining < GasPriceList.BaseCost) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientGas)); } StateSnapshot stateSnapshot = this.TakeSnapshot(); var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); uint160 address = this.GetNewAddress(); // Begin tracking the new intermediate state. We need to keep this reference around // for the scope of the transaction, so we can commit it later. IContractState state = this.CreateIntermediateState(); state.CreateAccount(address); ISmartContractState smartContractState = this.CreateSmartContractState(gasMeter, address, message, state); VmExecutionResult result = this.Vm.Create(state, smartContractState, code, parameters, type); this.GasRemaining -= gasMeter.GasConsumed; bool revert = result.ExecutionException != null; if (revert) { this.Rollback(stateSnapshot); return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.ExecutionException)); } state.Commit(); return(StateTransitionResult.Ok( gasMeter.GasConsumed, address, result.Result )); }
public void VM_CreateContract_WithParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- //Set the calldata for the transaction---------- var methodParameters = new object[] { (ulong)5 }; var callData = new CreateData((Gas)5000000, contractExecutionCode, methodParameters); Money value = Money.Zero; //------------------------------------------------------- var repository = new ContractStateRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractState track = repository.StartTracking(); var gasMeter = new GasMeter(callData.GasLimit); var transactionContext = new TransactionContext( txHash: uint256.One, blockHeight: 1, coinbase: TestAddress.ToUint160(this.network), sender: TestAddress.ToUint160(this.network), amount: value ); VmExecutionResult result = this.vm.Create(gasMeter, repository, callData, transactionContext); track.Commit(); var endBlockValue = track.GetStorageValue(result.NewContractAddress, Encoding.UTF8.GetBytes("EndBlock")); Assert.Equal(6, BitConverter.ToInt16(endBlockValue, 0)); Assert.Equal(TestAddress.ToUint160(this.network).ToBytes(), track.GetStorageValue(result.NewContractAddress, Encoding.UTF8.GetBytes("Owner"))); }
public InternalTransactionExecutor(ITransactionContext transactionContext, ISmartContractVirtualMachine vm, IContractLogHolder contractLogHolder, IContractState contractStateRepository, List <TransferInfo> internalTransferList, IKeyEncodingStrategy keyEncodingStrategy, ILoggerFactory loggerFactory, Network network) { this.transactionContext = transactionContext; this.contractLogHolder = contractLogHolder; this.contractStateRepository = contractStateRepository; this.internalTransferList = internalTransferList; this.keyEncodingStrategy = keyEncodingStrategy; this.loggerFactory = loggerFactory; this.logger = loggerFactory.CreateLogger(this.GetType()); this.network = network; this.vm = vm; }
public ReflectionVirtualMachineTests() { // Take what's needed for these tests var context = new ContractExecutorTestContext(); this.network = context.Network; this.vm = context.Vm; this.state = context.State; this.contractState = new SmartContractState( new Block(1, TestAddress), new Message(TestAddress, TestAddress, 0), new PersistentState(new PersistenceStrategy(this.state), context.ContractPrimitiveSerializer, TestAddress.ToUint160(this.network)), context.ContractPrimitiveSerializer, new GasMeter((Gas)5000000), new ContractLogHolder(this.network), Mock.Of <IInternalTransactionExecutor>(), new InternalHashHelper(), () => 1000); }
public ObserverTests() { var context = new ContractExecutorTestContext(); this.repository = context.State; this.network = context.Network; this.moduleReader = new ContractModuleDefinitionReader(); this.assemblyLoader = new ContractAssemblyLoader(); this.gasMeter = new GasMeter((Gas)5000000); var block = new TestBlock { Coinbase = TestAddress, Number = 1 }; var message = new TestMessage { ContractAddress = TestAddress, GasLimit = (Gas)GasLimit, Sender = TestAddress, Value = Value }; var getBalance = new Func <ulong>(() => Balance); var persistentState = new TestPersistentState(); var network = new SmartContractsRegTest(); var serializer = new ContractPrimitiveSerializer(network); this.state = new SmartContractState( new Stratis.SmartContracts.Core.Block(1, TestAddress), new Message(TestAddress, TestAddress, 0), new PersistentState(new MeteredPersistenceStrategy(this.repository, this.gasMeter, new BasicKeyEncodingStrategy()), context.ContractPrimitiveSerializer, TestAddress.ToUint160(this.network)), context.ContractPrimitiveSerializer, this.gasMeter, new ContractLogHolder(this.network), Mock.Of <IInternalTransactionExecutor>(), new InternalHashHelper(), () => 1000); this.rewriter = new ObserverRewriter(new Observer(this.gasMeter)); }
/// <inheritdoc /> public Transaction Process(IContractState stateSnapshot, uint160 contractAddress, ISmartContractTransactionContext transactionContext, IList <TransferInfo> internalTransfers, bool reversionRequired) { if (reversionRequired) { // Send back funds if (transactionContext.TxOutValue > 0) { return(CreateRefundTransaction(transactionContext)); } } // If contract received no funds and made no transfers, do nothing. if (transactionContext.TxOutValue == 0 && !internalTransfers.Any(x => x.Value > 0)) // TODO: In future discern whether we should even record internal transfers of 0. { return(null); } // If contract had no balance, received funds, but made no transfers, assign the current UTXO. if (stateSnapshot.GetUnspent(contractAddress) == null && transactionContext.TxOutValue > 0 && !internalTransfers.Any()) { stateSnapshot.SetUnspent(contractAddress, new ContractUnspentOutput { Value = transactionContext.TxOutValue, Hash = transactionContext.TransactionHash, Nvout = transactionContext.Nvout }); return(null); } // All other cases we need a condensing transaction var transactionCondenser = new TransactionCondenser(contractAddress, this.loggerFactory, internalTransfers, stateSnapshot, this.network, transactionContext); return(transactionCondenser.CreateCondensingTransaction()); }
public void VM_ExecuteContract_WithParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTestWithParameters.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- //Set the calldata for the transaction---------- var methodParameters = new object[] { (short)5 }; var callData = new CallData((Gas)5000000, new uint160(1), "StoreData", methodParameters); Money value = Money.Zero; //------------------------------------------------------- var repository = new ContractStateRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractState track = repository.StartTracking(); var gasMeter = new GasMeter(callData.GasLimit); uint160 address = TestAddress.ToUint160(this.network); var transactionContext = new TransactionContext(uint256.One, 1, address, address, value); repository.SetCode(callData.ContractAddress, contractExecutionCode); repository.SetContractType(callData.ContractAddress, "StorageTestWithParameters"); VmExecutionResult result = this.vm.ExecuteMethod(gasMeter, repository, callData, transactionContext); track.Commit(); Assert.Equal(5, BitConverter.ToInt16(track.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("orders")), 0)); Assert.Equal(5, BitConverter.ToInt16(repository.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("orders")), 0)); }
public void SmartContractList_ListEnumerationTest() { var listName = "testList"; var source = new MemoryDictionarySource(); var root = new ContractStateRoot(source); IContractState state = root.StartTracking(); IPersistenceStrategy persistenceStrategy = new PersistenceStrategy(state); var persistentState = new PersistentState( persistenceStrategy, this.contractPrimitiveSerializer, uint160.One); var list = new SmartContractList <string>(persistentState, listName); Assert.Equal((uint)0, list.Count); var items = new List <string> { "this is a test", "we should try to find a way", "to paramaterize our tests" }; foreach (var item in items) { // No AddRange list.Add(item); } Assert.Equal((uint)items.Count, list.Count); for (var i = 0; i < list.Count; i++) { Assert.Equal(items[i], list.GetValue((uint)i)); } }
/// <summary> /// Sets up the state object for the contract execution /// </summary> private ISmartContractState SetupState( IContractLogHolder contractLogger, List <TransferInfo> internalTransferList, IGasMeter gasMeter, IContractState repository, ITransactionContext transactionContext, uint160 contractAddress) { IPersistenceStrategy persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, new BasicKeyEncodingStrategy()); var persistentState = new PersistentState(persistenceStrategy, this.contractPrimitiveSerializer, contractAddress); IInternalTransactionExecutor internalTransactionExecutor = this.internalTransactionExecutorFactory.Create(this, contractLogger, repository, internalTransferList, transactionContext); var balanceState = new BalanceState(repository, transactionContext.Amount, internalTransferList); var contractState = new SmartContractState( new Block( transactionContext.BlockHeight, transactionContext.Coinbase.ToAddress(this.network) ), new Message( contractAddress.ToAddress(this.network), transactionContext.From.ToAddress(this.network), transactionContext.Amount ), persistentState, this.contractPrimitiveSerializer, gasMeter, contractLogger, internalTransactionExecutor, new InternalHashHelper(), () => balanceState.GetBalance(contractAddress)); return(contractState); }
/// <inheritdoc /> public async override Task RunAsync(RuleContext context) { this.Logger.LogTrace("()"); this.blockTxsProcessed = new List <Transaction>(); NBitcoin.Block block = context.ValidationContext.Block; ChainedHeader index = context.ValidationContext.ChainedHeader; DeploymentFlags flags = context.Flags; UnspentOutputSet view = ((UtxoRuleContext)context).UnspentOutputSet; this.Parent.PerformanceCounter.AddProcessedBlocks(1); // Start state from previous block's root this.ContractCoinviewRule.OriginalStateRoot.SyncToRoot(((SmartContractBlockHeader)context.ConsensusTip.Header).HashStateRoot.ToBytes()); IContractState trackedState = this.ContractCoinviewRule.OriginalStateRoot.StartTracking(); this.receipts = new List <Receipt>(); this.refundCounter = 1; long sigOpsCost = 0; Money fees = Money.Zero; var checkInputs = new List <Task <bool> >(); for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++) { this.Parent.PerformanceCounter.AddProcessedTransactions(1); Transaction tx = block.Transactions[txIndex]; if (!context.SkipValidation) { if (!this.IsProtocolTransaction(tx)) { if (!view.HaveInputs(tx)) { this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]"); ConsensusErrors.BadTransactionMissingInput.Throw(); } var prevheights = new int[tx.Inputs.Count]; // Check that transaction is BIP68 final. // BIP68 lock checks (as opposed to nLockTime checks) must // be in ConnectBlock because they require the UTXO set. for (int j = 0; j < tx.Inputs.Count; j++) { prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height; } if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags)) { this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]"); ConsensusErrors.BadTransactionNonFinal.Throw(); } } // GetTransactionSignatureOperationCost counts 3 types of sigops: // * legacy (always), // * p2sh (when P2SH enabled in flags and excludes coinbase), // * witness (when witness enabled in flags and excludes coinbase). sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags); if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost) { ConsensusErrors.BadBlockSigOps.Throw(); } if (!this.IsProtocolTransaction(tx)) { this.CheckInputs(tx, view, index.Height); fees += view.GetValueIn(tx) - tx.TotalOut; var txData = new PrecomputedTransactionData(tx); for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++) { this.Parent.PerformanceCounter.AddProcessedInputs(1); TxIn input = tx.Inputs[inputIndex]; int inputIndexCopy = inputIndex; TxOut txout = view.GetOutputFor(input); var checkInput = new Task <bool>(() => { if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall()) { return(input.ScriptSig.IsSmartContractSpend()); } var checker = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData); var ctx = new ScriptEvaluationContext(this.Parent.Network); ctx.ScriptVerify = flags.ScriptFlags; return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker)); }); checkInput.Start(); checkInputs.Add(checkInput); } } } this.UpdateCoinView(context, tx); this.blockTxsProcessed.Add(tx); } if (!context.SkipValidation) { this.CheckBlockReward(context, fees, index.Height, block); foreach (Task <bool> checkInput in checkInputs) { if (await checkInput.ConfigureAwait(false)) { continue; } this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]"); ConsensusErrors.BadTransactionScriptError.Throw(); } } else { this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height); } if (new uint256(this.ContractCoinviewRule.OriginalStateRoot.Root) != ((SmartContractBlockHeader)block.Header).HashStateRoot) { SmartContractConsensusErrors.UnequalStateRoots.Throw(); } ValidateAndStoreReceipts(((SmartContractBlockHeader)block.Header).ReceiptRoot); this.ContractCoinviewRule.OriginalStateRoot.Commit(); this.Logger.LogTrace("(-)"); }
///<inheritdoc /> public ICreateResult Create <T>(ISmartContractState smartContractState, ulong amountToTransfer, object[] parameters, ulong gasLimit = 0) { // TODO: Expend any neccessary costs. ulong gasBudget = (gasLimit != 0) ? gasLimit : DefaultGasLimit; // Ensure we have enough gas left to be able to fund the new GasMeter. if (smartContractState.GasMeter.GasAvailable < gasBudget) { throw new InsufficientGasException(); } var nestedGasMeter = new GasMeter((Gas)gasBudget); // Check balance. EnsureContractHasEnoughBalance(smartContractState, amountToTransfer); // Build objects for VM byte[] contractCode = this.contractStateRepository.GetCode(smartContractState.Message.ContractAddress.ToUint160(this.network)); // TODO: Fix this when calling from constructor. var context = new TransactionContext( this.transactionContext.TransactionHash, this.transactionContext.BlockHeight, this.transactionContext.Coinbase, smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, this.transactionContext.GetNonceAndIncrement()); IContractState track = this.contractStateRepository.StartTracking(); var createData = new CreateData(nestedGasMeter.GasLimit, contractCode, parameters); // Do create in vm VmExecutionResult result = this.vm.Create(nestedGasMeter, track, createData, context, typeof(T).Name); // Update parent gas meter. smartContractState.GasMeter.Spend(nestedGasMeter.GasConsumed); var revert = result.ExecutionException != null; if (revert) { this.logger.LogTrace("(-)[CONTRACT_EXECUTION_FAILED]"); track.Rollback(); return(CreateResult.Failed()); } this.logger.LogTrace("(-)[CONTRACT_EXECUTION_SUCCEEDED]"); track.Commit(); this.internalTransferList.Add(new TransferInfo { From = smartContractState.Message.ContractAddress.ToUint160(this.network), To = result.NewContractAddress, Value = amountToTransfer }); this.contractLogHolder.AddRawLogs(result.RawLogs); return(CreateResult.Succeeded(result.NewContractAddress.ToAddress(this.network))); }
/// <summary> /// Creates a new instance of a smart contract by invoking the contract's constructor /// </summary> public VmExecutionResult Create(IContractState repository, ISmartContractState contractState, byte[] contractCode, object[] parameters, string typeName = null) { this.logger.LogTrace("()"); string typeToInstantiate; ContractByteCode code; // Decompile the contract execution code and validate it. using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractCode)) { SmartContractValidationResult validation = moduleDefinition.Validate(this.validator); // If validation failed, refund the sender any remaining gas. if (!validation.IsValid) { this.logger.LogTrace("(-)[CONTRACT_VALIDATION_FAILED]"); return(VmExecutionResult.Error(new SmartContractValidationException(validation.Errors))); } typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name; moduleDefinition.InjectConstructorGas(); code = moduleDefinition.ToByteCode(); } Result <IContract> contractLoadResult = this.Load( code, typeToInstantiate, contractState.Message.ContractAddress.ToUint160(this.network), contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]"); return(VmExecutionResult.Error(exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address); // Set the code and the Type before the method is invoked repository.SetCode(contract.Address, contractCode); repository.SetContractType(contract.Address, typeToInstantiate); // Invoke the constructor of the provided contract code IContractInvocationResult invocationResult = contract.InvokeConstructor(parameters); if (!invocationResult.IsSuccess) { this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(new Exception("Constructor invocation failed!"))); } this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}", nameof(contract.Address), contract.Address); return(VmExecutionResult.Success(invocationResult.Return, typeToInstantiate)); }
public PersistenceStrategy(IContractState stateDb) { this.stateDb = stateDb; }
/// <summary> /// Invokes a method on an existing smart contract /// </summary> public VmExecutionResult ExecuteMethod( IGasMeter gasMeter, IContractState repository, ICallData callData, ITransactionContext transactionContext) { this.logger.LogTrace("(){0}:{1}", nameof(callData.MethodName), callData.MethodName); if (callData.MethodName == null) { this.logger.LogTrace("(-)[CALLCONTRACT_METHODNAME_NOT_GIVEN]"); return(VmExecutionResult.Error(gasMeter.GasConsumed, null)); } byte[] contractExecutionCode = repository.GetCode(callData.ContractAddress); string typeName = repository.GetContractType(callData.ContractAddress); if (contractExecutionCode == null) { return(VmExecutionResult.Error(gasMeter.GasConsumed, new SmartContractDoesNotExistException(callData.MethodName))); } // TODO consolidate this with CallData. MethodCall methodCall = new MethodCall(callData.MethodName, callData.MethodParameters); ContractByteCode code; using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractExecutionCode)) { moduleDefinition.InjectMethodGas(typeName, methodCall); code = moduleDefinition.ToByteCode(); } var internalTransferList = new List <TransferInfo>(); var contractLogger = new ContractLogHolder(this.network); ISmartContractState contractState = this.SetupState(contractLogger, internalTransferList, gasMeter, repository, transactionContext, callData.ContractAddress); Result <IContract> contractLoadResult = this.Load( code, typeName, callData.ContractAddress, contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address, callData); IContractInvocationResult invocationResult = contract.Invoke(methodCall); if (!invocationResult.IsSuccess) { this.logger.LogTrace("(-)[CALLCONTRACT_INSTANTIATION_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, new Exception("Method invocation failed!"))); } this.logger.LogTrace("[CALL_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Success(internalTransferList, gasMeter.GasConsumed, invocationResult.Return, contractLogger.GetRawLogs())); }
/// <summary> /// Creates a new instance of a smart contract by invoking the contract's constructor /// </summary> public VmExecutionResult Create(IGasMeter gasMeter, IContractState repository, ICreateData createData, ITransactionContext transactionContext, string typeName = null) { this.logger.LogTrace("()"); // TODO: Spend Validation + Creation Fee here. string typeToInstantiate; ContractByteCode code; // Decompile the contract execution code and validate it. using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(createData.ContractExecutionCode)) { SmartContractValidationResult validation = moduleDefinition.Validate(this.validator); // If validation failed, refund the sender any remaining gas. if (!validation.IsValid) { this.logger.LogTrace("(-)[CONTRACT_VALIDATION_FAILED]"); return(VmExecutionResult.Error(gasMeter.GasConsumed, new SmartContractValidationException(validation.Errors))); } typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name; moduleDefinition.InjectConstructorGas(); code = moduleDefinition.ToByteCode(); } var internalTransferList = new List <TransferInfo>(); uint160 address = this.addressGenerator.GenerateAddress(transactionContext.TransactionHash, transactionContext.GetNonceAndIncrement()); var contractLogger = new ContractLogHolder(this.network); ISmartContractState contractState = this.SetupState(contractLogger, internalTransferList, gasMeter, repository, transactionContext, address); Result <IContract> contractLoadResult = this.Load( code, typeToInstantiate, address, contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address, createData); // Create an account for the contract in the state repository. repository.CreateAccount(contract.Address); // Invoke the constructor of the provided contract code IContractInvocationResult invocationResult = contract.InvokeConstructor(createData.MethodParameters); if (!invocationResult.IsSuccess) { this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(gasMeter.GasConsumed, new Exception("Constructor invocation failed!"))); } this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}, {2}={3}", nameof(contract.Address), contract.Address, nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); repository.SetCode(contract.Address, createData.ContractExecutionCode); repository.SetContractType(contract.Address, contract.Type.Name); return(VmExecutionResult.CreationSuccess(contract.Address, internalTransferList, gasMeter.GasConsumed, invocationResult.Return, contractLogger.GetRawLogs())); }