Skip to content

Commit

Permalink
included uts
Browse files Browse the repository at this point in the history
  • Loading branch information
meevee98 committed Dec 12, 2019
1 parent 390ade4 commit 8dc6fba
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/neo/SmartContract/InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,9 @@ private static bool PutEx(ApplicationEngine engine, StorageContext context, byte
StorageItem item = engine.Snapshot.Storages.GetAndChange(skey, () => new StorageItem());
item.Value = value;
item.IsConstant = flags.HasFlag(StorageFlags.Constant);
if (value.Length < currentOccupiedBytes)
if (item.Size < currentOccupiedBytes)
{
releasedBytes = currentOccupiedBytes - value.Length;
releasedBytes = currentOccupiedBytes - item.Size;
reusedBytes = currentOccupiedBytes - releasedBytes;
}
else
Expand Down
155 changes: 155 additions & 0 deletions tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM.Types;
using System;

Expand Down Expand Up @@ -74,6 +75,160 @@ public void TestNotify()
item.Should().Be(null);
}

[TestMethod]
public void TestStorageReused()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);

var reuseDiscount = NativeContract.Policy.GetDiscountPerByteReused(snapshot);
var releaseDiscount = NativeContract.Policy.GetDiscountPerByteReleased(snapshot);

var storageContext = InitiateEngineStorage(snapshot, engine);

// first storage put
// shouldn't be discounted
var gasBeforeFirstPut = engine.GasConsumed;

var key = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 };
var value1 = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
var storageItem1 = new StorageItem
{
Value = value1,
IsConstant = false
};

engine.CurrentContext.EvaluationStack.Push(value1);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeFirstPut);

// update storage put with the bigger size than the previous
// should be discounted the reuse of the previous size
var gasBeforeBiggerSizeUpdate = engine.GasConsumed;

var value2 = new byte[] { 0x01, 0x02, 0x04, 0x03, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C };
var storageItem2 = new StorageItem
{
Value = value2,
IsConstant = false
};

engine.CurrentContext.EvaluationStack.Push(value2);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeBiggerSizeUpdate - (storageItem1.Size * reuseDiscount));

// update storage put with the same size as the previous
// should be discounted the reuse of the previous size
var gasBeforeSameSizeUpdate = engine.GasConsumed;

engine.CurrentContext.EvaluationStack.Push(value2);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeSameSizeUpdate - (storageItem2.Size * reuseDiscount));

// update storage put with the smaller size than the previous
// should be discounted the reuse of the new size and the release of the difference between sizes
var gasBeforeSmallerSizeUpdate = engine.GasConsumed;

var value3 = new byte[] { 0x01, 0x02 };
var storageItem3 = new StorageItem
{
Value = value3,
IsConstant = false
};
var diff = value2.Length - value3.Length;

engine.CurrentContext.EvaluationStack.Push(value3);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeSmallerSizeUpdate - (storageItem3.Size * reuseDiscount + diff * releaseDiscount));
}

[TestMethod]
public void TestStorageReleased()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);

var reuseDiscount = NativeContract.Policy.GetDiscountPerByteReused(snapshot);
var releaseDiscount = NativeContract.Policy.GetDiscountPerByteReleased(snapshot);
var storageContext = InitiateEngineStorage(snapshot, engine);

// first storage put
// shouldn't be discounted
var gasBeforeFirstPut = engine.GasConsumed;

var key = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 };
var value1 = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
var storageItem1 = new StorageItem
{
Value = value1,
IsConstant = false
};

engine.CurrentContext.EvaluationStack.Push(value1);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeFirstPut);

// update storage put with the smaller size than the previous
// should be discounted the reuse of the new size and the release of the difference between sizes
var gasBeforeSmallerSizeUpdate = engine.GasConsumed;

var value2 = new byte[] { 0x01, 0x02 };
var storageItem2 = new StorageItem
{
Value = value2,
IsConstant = false
};
var diff = value1.Length - value2.Length;

engine.CurrentContext.EvaluationStack.Push(value2);
engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeSmallerSizeUpdate - (storageItem2.Size * reuseDiscount + diff * releaseDiscount));

// call to storage delete
// should be discounted the release of the previous size
var gasBeforeDeletion = engine.GasConsumed;

engine.CurrentContext.EvaluationStack.Push(key);
engine.CurrentContext.EvaluationStack.Push(new InteropInterface<StorageContext>(storageContext));

InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeTrue();
engine.GasConsumed.Should().Be(gasBeforeDeletion - (storageItem2.Size * releaseDiscount));
}

private StorageContext InitiateEngineStorage(SnapshotView snapshot, ApplicationEngine engine)
{
var contract = TestUtils.GetContract();
contract.Manifest.Features = Neo.SmartContract.Manifest.ContractFeatures.HasStorage;

var storageContext = new StorageContext
{
ScriptHash = contract.ScriptHash,
IsReadOnly = false
};
snapshot.Contracts.Add(contract.ScriptHash, contract);
engine.LoadScript(new byte[] { 0x01 });

return storageContext;
}

[TestMethod]
public void TestDisposable()
{
Expand Down

0 comments on commit 8dc6fba

Please sign in to comment.