Skip to content

Commit

Permalink
[Add] Transaction Builder (#3477)
Browse files Browse the repository at this point in the history
* Added Builders with tests

* Added SignerBuilder and started WitnessRuleBuilder

* Added `WitnessConditionBuilder` with tests

* Added more logic

* Fixed `SignerBuilder` class

* Code touch ups

* Added more tests

* Update src/Neo/Builders/TransactionBuilder.cs

* Fixed `And` `Or` and `Not` conditions

* Fixed Memory leak

* Added error message for Witness scripts

---------

Co-authored-by: Jimmy <[email protected]>
Co-authored-by: Shargon <[email protected]>
Co-authored-by: NGD Admin <[email protected]>
  • Loading branch information
4 people authored Sep 27, 2024
1 parent d6ed5a5 commit 73cea01
Show file tree
Hide file tree
Showing 14 changed files with 1,471 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/Neo/Builders/AndConditionBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// AndConditionBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

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

namespace Neo.Builders
{
public sealed class AndConditionBuilder
{
private readonly AndCondition _condition = new() { Expressions = [] };

private AndConditionBuilder() { }

public static AndConditionBuilder CreateEmpty()
{
return new AndConditionBuilder();
}

public AndConditionBuilder And(Action<AndConditionBuilder> config)
{
var acb = new AndConditionBuilder();
config(acb);

_condition.Expressions = [.. _condition.Expressions, acb.Build()];

return this;
}

public AndConditionBuilder Or(Action<OrConditionBuilder> config)
{
var ocb = OrConditionBuilder.CreateEmpty();
config(ocb);

_condition.Expressions = [.. _condition.Expressions, ocb.Build()];

return this;
}

public AndConditionBuilder Boolean(bool expression)
{
_condition.Expressions = [.. _condition.Expressions, new BooleanCondition { Expression = expression }];
return this;
}

public AndConditionBuilder CalledByContract(UInt160 hash)
{
_condition.Expressions = [.. _condition.Expressions, new CalledByContractCondition { Hash = hash }];
return this;
}

public AndConditionBuilder CalledByEntry()
{
_condition.Expressions = [.. _condition.Expressions, new CalledByEntryCondition()];
return this;
}

public AndConditionBuilder CalledByGroup(ECPoint publicKey)
{
_condition.Expressions = [.. _condition.Expressions, new CalledByGroupCondition { Group = publicKey }];
return this;
}

public AndConditionBuilder Group(ECPoint publicKey)
{
_condition.Expressions = [.. _condition.Expressions, new GroupCondition() { Group = publicKey }];
return this;
}

public AndConditionBuilder ScriptHash(UInt160 scriptHash)
{
_condition.Expressions = [.. _condition.Expressions, new ScriptHashCondition() { Hash = scriptHash }];
return this;
}

public AndCondition Build()
{
return _condition;
}
}
}
90 changes: 90 additions & 0 deletions src/Neo/Builders/OrConditionBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// OrConditionBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

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

namespace Neo.Builders
{
public sealed class OrConditionBuilder
{
private readonly OrCondition _condition = new() { Expressions = [] };

private OrConditionBuilder() { }

public static OrConditionBuilder CreateEmpty()
{
return new OrConditionBuilder();
}

public OrConditionBuilder And(Action<AndConditionBuilder> config)
{
var acb = AndConditionBuilder.CreateEmpty();
config(acb);

_condition.Expressions = [.. _condition.Expressions, acb.Build()];

return this;
}

public OrConditionBuilder Or(Action<OrConditionBuilder> config)
{
var acb = new OrConditionBuilder();
config(acb);

_condition.Expressions = [.. _condition.Expressions, acb.Build()];

return this;
}

public OrConditionBuilder Boolean(bool expression)
{
_condition.Expressions = [.. _condition.Expressions, new BooleanCondition { Expression = expression }];
return this;
}

public OrConditionBuilder CalledByContract(UInt160 hash)
{
_condition.Expressions = [.. _condition.Expressions, new CalledByContractCondition { Hash = hash }];
return this;
}

public OrConditionBuilder CalledByEntry()
{
_condition.Expressions = [.. _condition.Expressions, new CalledByEntryCondition()];
return this;
}

public OrConditionBuilder CalledByGroup(ECPoint publicKey)
{
_condition.Expressions = [.. _condition.Expressions, new CalledByGroupCondition { Group = publicKey }];
return this;
}

public OrConditionBuilder Group(ECPoint publicKey)
{
_condition.Expressions = [.. _condition.Expressions, new GroupCondition() { Group = publicKey }];
return this;
}

public OrConditionBuilder ScriptHash(UInt160 scriptHash)
{
_condition.Expressions = [.. _condition.Expressions, new ScriptHashCondition() { Hash = scriptHash }];
return this;
}

public OrCondition Build()
{
return _condition;
}
}
}
73 changes: 73 additions & 0 deletions src/Neo/Builders/SignerBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// SignerBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

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

namespace Neo.Builders
{
public sealed class SignerBuilder
{
private readonly Signer _signer = new Signer()
{
Account = UInt160.Zero,
AllowedContracts = [],
AllowedGroups = [],
Rules = [],
Scopes = WitnessScope.None,
};

private SignerBuilder() { }

public static SignerBuilder CreateEmpty()
{
return new SignerBuilder();
}

public SignerBuilder Account(UInt160 scriptHash)
{
_signer.Account = scriptHash;
return this;
}

public SignerBuilder AllowContract(UInt160 contractHash)
{
_signer.AllowedContracts = [.. _signer.AllowedContracts, contractHash];
return this;
}

public SignerBuilder AllowGroup(ECPoint publicKey)
{
_signer.AllowedGroups = [.. _signer.AllowedGroups, publicKey];
return this;
}

public SignerBuilder AddWitnessScope(WitnessScope scope)
{
_signer.Scopes |= scope;
return this;
}

public SignerBuilder AddWitnessRule(WitnessRuleAction action, Action<WitnessRuleBuilder> config)
{
var rb = WitnessRuleBuilder.Create(action);
config(rb);
_signer.Rules = [.. _signer.Rules, rb.Build()];
return this;
}

public Signer Build()
{
return _signer;
}
}
}
74 changes: 74 additions & 0 deletions src/Neo/Builders/TransactionAttributesBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// TransactionAttributesBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Network.P2P.Payloads;
using System;
using System.Linq;

namespace Neo.Builders
{
public sealed class TransactionAttributesBuilder
{
private TransactionAttribute[] _attributes = [];

private TransactionAttributesBuilder() { }

public static TransactionAttributesBuilder CreateEmpty()
{
return new TransactionAttributesBuilder();
}

public TransactionAttributesBuilder AddConflict(Action<Conflicts> config)
{
var conflicts = new Conflicts();
config(conflicts);
_attributes = [.. _attributes, conflicts];
return this;
}

public TransactionAttributesBuilder AddOracleResponse(Action<OracleResponse> config)
{
var oracleResponse = new OracleResponse();
config(oracleResponse);
_attributes = [.. _attributes, oracleResponse];
return this;
}

public TransactionAttributesBuilder AddHighPriority()
{
if (_attributes.Any(a => a is HighPriorityAttribute))
throw new InvalidOperationException("HighPriority already exists in the attributes.");

var highPriority = new HighPriorityAttribute();
_attributes = [.. _attributes, highPriority];
return this;
}

public TransactionAttributesBuilder AddNotValidBefore(uint block)
{
if (_attributes.Any(a => a is NotValidBefore b && b.Height == block))
throw new InvalidOperationException($"Block {block} already exists in the attributes.");

var validUntilBlock = new NotValidBefore()
{
Height = block
};

_attributes = [.. _attributes, validUntilBlock];
return this;
}

public TransactionAttribute[] Build()
{
return _attributes;
}
}
}
Loading

0 comments on commit 73cea01

Please sign in to comment.