Skip to content
This repository has been archived by the owner on Apr 6, 2020. It is now read-only.

Fix #306 and Fix #362 #430

Merged
merged 1 commit into from
Sep 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/NeoSharp.Core/Blockchain/Genesis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static Genesis()
};

var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default);
var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager);
var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager, null, null, null);

var blockOperationsManager = new BlockOperationsManager(
Crypto.Default,
Expand Down
4 changes: 2 additions & 2 deletions src/NeoSharp.Core/Blockchain/GenesisAssets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static GenesisAssets()
Witness = new Witness[0]
};

new TransactionOperationsManager(Crypto.Default, witnessOperationManager)
new TransactionOperationsManager(Crypto.Default, witnessOperationManager, null, null, null)
.Sign(GoverningTokenRegisterTransaction);

// GAS Token is represented as a RegisterTransaction of type UtilityToken
Expand All @@ -61,7 +61,7 @@ static GenesisAssets()
Witness = new Witness[0]
};

new TransactionOperationsManager(Crypto.Default, witnessOperationManager)
new TransactionOperationsManager(Crypto.Default, witnessOperationManager, null, null, null)
.Sign(UtilityTokenRegisterTransaction);

var builder = new ConfigurationBuilder()
Expand Down
2 changes: 2 additions & 0 deletions src/NeoSharp.Core/DI/Modules/BlockchainModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using NeoSharp.Core.Blockchain.State;
using NeoSharp.Core.Models;
using NeoSharp.Core.Models.OperationManger;
using NeoSharp.Core.Types;

namespace NeoSharp.Core.DI.Modules
{
Expand All @@ -21,6 +22,7 @@ public void Register(IContainerBuilder containerBuilder)
containerBuilder.RegisterSingleton<IBlockPool, BlockPool>();
containerBuilder.RegisterSingleton<IComparer<Transaction>, TransactionComparer>();
containerBuilder.RegisterSingleton<ITransactionPool, TransactionPool>();
containerBuilder.RegisterSingleton<ITransactionContext, TransactionContext>();
containerBuilder.RegisterSingleton<ITransactionPersister<Transaction>, TransactionPersister>();

containerBuilder.RegisterSingleton<ITransactionPersister<ClaimTransaction>, ClaimTransactionPersister>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
using NeoSharp.BinarySerialization;
using System;
using System.Collections.Generic;
using System.Linq;
using NeoSharp.BinarySerialization;
using NeoSharp.Core.Blockchain;
using NeoSharp.Core.Blockchain.Processing;
using NeoSharp.Core.Cryptography;
using NeoSharp.Core.Extensions;
using NeoSharp.Core.Types;

namespace NeoSharp.Core.Models.OperationManger
Expand All @@ -9,35 +15,197 @@ public class TransactionOperationsManager : ITransactionOperationsManager
#region Private Fields
private readonly Crypto _crypto;
private readonly IWitnessOperationsManager _witnessOperationsManager;
private readonly ITransactionPool _transactionPool;
private readonly IBlockchain _blockchain;
private readonly ITransactionContext _transactionContext;
#endregion

#region Constructor
public TransactionOperationsManager(Crypto crypto, IWitnessOperationsManager witnessOperationsManager)
public TransactionOperationsManager(Crypto crypto, IWitnessOperationsManager witnessOperationsManager,
ITransactionPool transactionPool, IBlockchain blockchain, ITransactionContext transactionContext)
{
this._crypto = crypto;
this._witnessOperationsManager = witnessOperationsManager;
_crypto = crypto;
_witnessOperationsManager = witnessOperationsManager;
_transactionPool = transactionPool;
_blockchain = blockchain;
_transactionContext = transactionContext;
}
#endregion

#region ITransactionOperationsManager implementation
public void Sign(Transaction transaction)
{
transaction.Hash = new UInt256(this._crypto.Hash256(BinarySerializer.Default.Serialize(transaction, new BinarySerializerSettings
transaction.Hash = new UInt256(_crypto.Hash256(BinarySerializer.Default.Serialize(transaction, new BinarySerializerSettings
{
Filter = a => a != nameof(transaction.Witness)
})));

if (transaction.Witness == null) return;
foreach (var witness in transaction.Witness)
{
this._witnessOperationsManager.Sign(witness);
_witnessOperationsManager.Sign(witness);
}
}

public bool Verify(Transaction transaction)
{
throw new System.NotImplementedException();
if (transaction.Attributes.Any(p =>
p.Usage == TransactionAttributeUsage.ECDH02 || p.Usage == TransactionAttributeUsage.ECDH03))
{
return false;
}

for (var i = 1; i < transaction.Inputs.Length; i++)
{
for (var j = 0; j < i; j++)
{
if (transaction.Inputs[i].PrevHash == transaction.Inputs[j].PrevHash
&& transaction.Inputs[i].PrevIndex == transaction.Inputs[j].PrevIndex)
{
return false;
}
}
}

if (_transactionPool
.Where(p => p != transaction)
.SelectMany(p => p.Inputs)
.Intersect(transaction.Inputs)
.Any())
{
return false;
}

if (_blockchain.IsDoubleSpend(transaction))
{
return false;
}

foreach (var group in transaction.Outputs.GroupBy(p => p.AssetId))
{
var asset = _blockchain.GetAsset(group.Key).Result;

if (asset == null)
{
return false;
}

// TODO: Should we check for `asset.Expiration <= _blockchain.Height + 1` ??
if (asset.AssetType != AssetType.GoverningToken
&& asset.AssetType != AssetType.UtilityToken)
{
return false;
}

var tenPoweredToEightMinusAssetPrecision = (long) Math.Pow(10, 8 - asset.Precision);

if (group.Any(output => output.Value.Value % tenPoweredToEightMinusAssetPrecision != 0))
{
return false;
}
}

var results = GetTransactionResults(transaction)?.ToArray();

if (results == null)
{
return false;
}

var resultsDestroy = results.Where(p => p.Amount > Fixed8.Zero).ToArray();

if (resultsDestroy.Length > 1)
{
return false;
}

if (resultsDestroy.Length == 1
&& resultsDestroy[0].AssetId != _transactionContext.UtilityTokenHash)
{
return false;
}

if (_transactionContext.SystemFee > Fixed8.Zero
&& (resultsDestroy.Length == 0
|| resultsDestroy[0].Amount < _transactionContext.SystemFee))
{
return false;
}

var resultsIssue = results.Where(p => p.Amount < Fixed8.Zero).ToArray();

if (resultsIssue.Any(p => p.AssetId != _transactionContext.UtilityTokenHash)
&& (transaction.Type == TransactionType.ClaimTransaction
|| transaction.Type == TransactionType.IssueTransaction))
{
return false;
}

if (transaction.Type != TransactionType.MinerTransaction
&& resultsIssue.Length > 0)
{
return false;
}

// TODO: Verify Receiving Scripts?

if (transaction.Witness.Any(witness => !_witnessOperationsManager.Verify(witness)))
{
return false;
}

return true;
}

private IEnumerable<TransactionResult> GetTransactionResults(Transaction transaction)
{
return GetReferences(transaction)?.Values.Select(p => new
{
p.AssetId,
p.Value
}).Concat(transaction.Outputs.Select(p => new
{
p.AssetId,
Value = -p.Value
})).GroupBy(p => p.AssetId, (k, g) => new TransactionResult
{
AssetId = k,
Amount = g.Sum(p => p.Value)
}).Where(p => p.Amount != Fixed8.Zero);
}

private class TransactionResult
{
public UInt256 AssetId;
public Fixed8 Amount;
}

private Dictionary<CoinReference, TransactionOutput> GetReferences(Transaction transaction)
{
var references = new Dictionary<CoinReference, TransactionOutput>();

foreach (var group in transaction.Inputs.GroupBy(p => p.PrevHash))
{
var tx = _blockchain.GetTransaction(group.Key).Result;

if (tx == null)
{
references = null;
break;
}

foreach (var p in group)
{
if (tx.Outputs.Length > p.PrevIndex)
{
references.Add(p, tx.Outputs[p.PrevIndex]);
}
}
}

return references;
}

#endregion
}
}
15 changes: 15 additions & 0 deletions src/NeoSharp.Core/Types/ITransactionContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Linq;
using NeoSharp.Core.Blockchain;
using NeoSharp.Core.Models;

namespace NeoSharp.Core.Types
{
public interface ITransactionContext
{
Fixed8 DefaultSystemFee { get; }
UInt256 UtilityTokenHash { get; }
UInt256 GoverningTokenHash { get; }
Fixed8 SystemFee { get; }
}
}
9 changes: 4 additions & 5 deletions src/NeoSharp.Core/Types/TransactionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@

namespace NeoSharp.Core.Types
{
public class TransactionContext
public class TransactionContext : ITransactionContext
{
// TODO #362: How to inject this

public static readonly Fixed8 DefaultSystemFee = Fixed8.Zero;// Settings.Default.SystemFee.TryGetValue(Type, out Fixed8 fee) ? fee : Fixed8.Zero;
public static readonly UInt256 UtilityTokenHash = UInt256.Zero, GoverningTokenHash = UInt256.Zero;
public Fixed8 DefaultSystemFee => Fixed8.Zero; // Settings.Default.SystemFee.TryGetValue(Type, out Fixed8 fee) ? fee : Fixed8.Zero;
public UInt256 UtilityTokenHash => UInt256.Zero;
public UInt256 GoverningTokenHash => UInt256.Zero;

// ---------------------------

Expand Down
Loading