Skip to content

Commit

Permalink
Refuel (#2444)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzhang authored Apr 24, 2021
1 parent 7e2d435 commit 4d45a79
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public partial class ApplicationEngine : ExecutionEngine

private static IApplicationEngineProvider applicationEngineProvider;
private static Dictionary<uint, InteropDescriptor> services;
private readonly long gas_amount;
private long gas_amount;
private List<NotifyEventArgs> notifications;
private List<IDisposable> disposables;
private readonly Dictionary<UInt160, int> invocationCounter = new();
Expand Down Expand Up @@ -147,6 +147,14 @@ protected internal void AddGas(long gas)
throw new InvalidOperationException("Insufficient GAS.");
}

internal void Refuel(long gas)
{
checked
{
gas_amount += gas;
}
}

protected override void OnFault(Exception ex)
{
FaultException = ex;
Expand Down
12 changes: 12 additions & 0 deletions src/neo/SmartContract/Native/GasToken.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma warning disable IDE0051

using Neo.Cryptography.ECC;
using Neo.Network.P2P.Payloads;
using System;

namespace Neo.SmartContract.Native
{
Expand Down Expand Up @@ -33,5 +36,14 @@ internal override async ContractTask OnPersist(ApplicationEngine engine)
UInt160 primary = Contract.CreateSignatureRedeemScript(validators[engine.PersistingBlock.PrimaryIndex]).ToScriptHash();
await Mint(engine, primary, totalNetworkFee, false);
}

[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
private async ContractTask Refuel(ApplicationEngine engine, UInt160 account, long amount)
{
if (amount < 0) throw new ArgumentOutOfRangeException(nameof(amount));
if (!engine.CheckWitnessInternal(account)) throw new InvalidOperationException();
await Burn(engine, account, amount);
engine.Refuel(amount);
}
}
}
62 changes: 62 additions & 0 deletions tests/neo.UnitTests/SmartContract/Native/UT_GasToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.UnitTests.Extensions;
using Neo.VM;
using System;
using System.Linq;
using System.Numerics;
Expand Down Expand Up @@ -35,6 +36,67 @@ public void TestSetup()
[TestMethod]
public void Check_Decimals() => NativeContract.GAS.Decimals(_snapshot).Should().Be(8);

[TestMethod]
public void Refuel()
{
// Prepare

var wallet = TestUtils.GenerateTestWallet();
var snapshot = TestBlockchain.GetTestSnapshot();

using var unlock = wallet.Unlock("");
var accBalance = wallet.CreateAccount();
var accNoBalance = wallet.CreateAccount();

// Fake balance

var key = NativeContract.GAS.CreateStorageKey(20, accNoBalance.ScriptHash);
var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
entry.GetInteroperable<AccountState>().Balance = 1 * NativeContract.GAS.Factor;

key = NativeContract.GAS.CreateStorageKey(20, accBalance.ScriptHash);
entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
entry.GetInteroperable<AccountState>().Balance = 100 * NativeContract.GAS.Factor;

snapshot.Commit();

// Make transaction

byte[] script;
using (ScriptBuilder sb = new())
{
sb.EmitDynamicCall(NativeContract.GAS.Hash, "refuel", accBalance.ScriptHash, 100 * NativeContract.GAS.Factor);
sb.Emit(OpCode.DROP);
sb.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft);
script = sb.ToArray();
}

var signers = new Signer[]{ new Signer
{
Account = accBalance.ScriptHash,
Scopes = WitnessScope.CalledByEntry
} ,
new Signer
{
Account = accNoBalance.ScriptHash,
Scopes = WitnessScope.CalledByEntry
} };

var tx = wallet.MakeTransaction(snapshot, script, accBalance.ScriptHash, signers);
Assert.IsNotNull(tx);

// Check

using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee);
engine.LoadScript(tx.Script);
Assert.AreEqual(VMState.HALT, engine.Execute());
Assert.AreEqual(1, engine.ResultStack.Count);
Assert.AreEqual(100_00300140, engine.ResultStack.Pop().GetInteger());

entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
Assert.AreEqual(0, entry.GetInteroperable<AccountState>().Balance);
}

[TestMethod]
public async Task Check_BalanceOfTransferAndBurn()
{
Expand Down

0 comments on commit 4d45a79

Please sign in to comment.