Skip to content

Commit

Permalink
Merge branch 'stop_using_parser_combinator' into miniscript_final_ver…
Browse files Browse the repository at this point in the history
…sion_rust
  • Loading branch information
joemphilips committed Nov 8, 2019
2 parents beb91c4 + e99259b commit a5dd29b
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 83 deletions.
25 changes: 21 additions & 4 deletions NBitcoin.Tests/MiniscriptTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,22 @@ public void PolicyParserTest()

var strOr = $"or(99@pk({PubKeys[0]}),pk({PubKeys[1]}))";
// var strOr = $"or(pk({PubKeys[0]}),pk({PubKeys[1]}))";
var msRealOr = ConcretePolicy<PubKey, uint160>.Parse(strOr);
Assert.True(msRealOr.IsValid());
var orRes = ConcretePolicy<PubKey, uint160>.Parse(strOr);
Assert.True(orRes.IsValid());

var strNestedOr = $"or(after(3),{strOr})";
var nestedOrRes = ConcretePolicy<PubKey, uint160>.Parse(strNestedOr);
Assert.True(nestedOrRes.IsValid());

var strAnd = $"and(older(3),{strNestedOr})";
var andRes = ConcretePolicy<PubKey, uint160>.Parse(strAnd);
Assert.True(andRes.IsValid());

var hash256 = Crypto.Hashes.Hash256(PubKeys[2].ToBytes()).ToString();
var hash160 = Crypto.Hashes.Hash160(PubKeys[2].ToBytes()).ToString();
var strThresh = $"thresh(2,hash256({hash256}),{strAnd},hash160({hash160}))";
var threshRes = ConcretePolicy<PubKey,uint160>.Parse(strThresh);
Assert.True(threshRes.IsValid());
}

[Fact]
Expand All @@ -224,11 +238,14 @@ public void MiniscriptParserTest()
{
var pkStr = $"c:pk({PubKeys[0]})";
var orStr = $"or_b(c:pk({PubKeys[0]}),sc:pk({PubKeys[1]}))";
var andStr = $"and(time(3),{orStr})";
// var andStr = $"";
// var orMs = Miniscript<PubKey, uint160>.Parse(orStr);
var pkRes = MiniscriptDSLParser<PubKey, uint160>.ParseTerminal(pkStr);
Assert.True(pkRes is Terminal<PubKey, uint160>.Check c && (c.Item.Node is Terminal<PubKey, uint160>.Pk));

var orRes = MiniscriptDSLParser<PubKey, uint160>.ParseTerminal(orStr);
var andRes = MiniscriptDSLParser<PubKey, uint160>.ParseTerminal(andStr);
Assert.True(orRes is Terminal<PubKey, uint160>.OrB);
// var andRes = MiniscriptDSLParser<PubKey, uint160>.ParseTerminal(andStr);
}
}
}
28 changes: 25 additions & 3 deletions NBitcoin/Scripting/Miniscript/AstElem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,14 @@ public ThreshM(uint item1, TPk[] item2): base(Tags.ThreshM)

public static Terminal<TPk, TPKh> NewTrue() => Terminal<TPk, TPKh>.True;
public static Terminal<TPk, TPKh> NewFalse() => Terminal<TPk, TPKh>.False;
public static Terminal<TPk, TPKh> NewPk(TPk item) => new Pk(item);
public static Terminal<TPk, TPKh> NewPk(TPk item)
{
if (item is null)
throw new ArgumentNullException(nameof(item));

return new Pk(item);
}

public static Terminal<TPk, TPKh> NewPkH(TPKh item) => new PkH(item);
public static Terminal<TPk, TPKh> NewAfter(uint item) => new After(item);
public static Terminal<TPk, TPKh> NewOlder(uint item) => new Older(item);
Expand All @@ -328,7 +335,14 @@ public static Terminal<TPk, TPKh> NewHash160(uint160 item)
=> new Hash160(item);
public static Terminal<TPk, TPKh> NewAlt(Miniscript<TPk, TPKh> item) => new Terminal<TPk, TPKh>.Alt(item);
public static Terminal<TPk, TPKh> NewSwap(Miniscript<TPk, TPKh> item) => new Terminal<TPk, TPKh>.Swap(item);
public static Terminal<TPk, TPKh> NewCheck(Miniscript<TPk, TPKh> item) => new Terminal<TPk, TPKh>.Check(item);
public static Terminal<TPk, TPKh> NewCheck(Miniscript<TPk, TPKh> item)
{
if (item is null)
throw new ArgumentNullException(nameof(item));

return new Check(item);
}

public static Terminal<TPk, TPKh> NewDupIf(Miniscript<TPk, TPKh> item) => new DupIf(item);
public static Terminal<TPk, TPKh> NewVerify(Miniscript<TPk, TPKh> item) => new Verify(item);
public static Terminal<TPk, TPKh> NewNonZero(Miniscript<TPk, TPKh> item) => new NonZero(item);
Expand All @@ -344,7 +358,15 @@ public static Terminal<TPk, TPKh> NewAndOr(Miniscript<TPk, TPKh> item1, Miniscri
=> new AndOr(item1, item2, item3);

public static Terminal<TPk, TPKh> NewOrB(Miniscript<TPk, TPKh> item1, Miniscript<TPk, TPKh> item2)
=> new OrB(item1, item2);
{
if (item1 is null)
throw new ArgumentNullException(nameof(item1));

if (item2 is null)
throw new ArgumentNullException(nameof(item2));

return new OrB(item1, item2);
}

public static Terminal<TPk, TPKh> NewOrD(Miniscript<TPk, TPKh> item1, Miniscript<TPk, TPKh> item2)
=> new OrD(item1, item2);
Expand Down
53 changes: 31 additions & 22 deletions NBitcoin/Scripting/Miniscript/MiniscriptDSLParser.Terminal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,20 @@ from t in ExprP("hash160").Then(s => TryConvert(s, uint160.Parse))
private static Parser<char, Terminal<TPk, TPKh>> PWrapper(char identifier,
Func<Miniscript<TPk, TPKh>, Terminal<TPk, TPKh>> construct)
=>
from _t in Parse.Char(identifier).Then(_ => Parse.Char(':'))
from inner in Parse.Ref(() => TerminalDSLParser)
.Except(PWrapper(identifier, construct)) // should not have the same wrapper twice
select construct(Miniscript<TPk, TPKh>.FromAst(inner));
(from _t in Parse.Char(identifier).Then(_ => Parse.Char(':'))
from inner in Parse.Ref(PNonWrappers)
select construct(Miniscript<TPk, TPKh>.FromAst(inner)))
.Or(
from _t in Parse.Char(identifier)
from x in Parse.Ref(() => PWrappers).Except(PWrapper(identifier, construct))
select x
);

private static Parser<char, Terminal<TPk, TPKh>> PBinary(
string identifier,
Func<Miniscript<TPk, TPKh>, Miniscript<TPk, TPKh>, Terminal<TPk, TPKh>> constructor
) =>
from s in PSubExprs(identifier, () => TerminalDSLParser)
from s in PSubExprs(identifier, TerminalDSLParser)
where s.Count() == 2
select constructor(Miniscript<TPk, TPKh>.FromAst(s.ElementAt(0)),
Miniscript<TPk, TPKh>.FromAst(s.ElementAt(1)));
Expand All @@ -71,7 +75,7 @@ private static Parser<char, Terminal<TPk, TPKh>> PTernary(
string identifier,
Func<Miniscript<TPk, TPKh>, Miniscript<TPk, TPKh>, Miniscript<TPk, TPKh>, Terminal<TPk, TPKh>> constructor
) =>
from s in PSubExprs(identifier, () => TerminalDSLParser)
from s in PSubExprs(identifier, TerminalDSLParser)
where s.Count() == 3
select constructor(
Miniscript<TPk, TPKh>.FromAst(s.ElementAt(0)),
Expand All @@ -82,30 +86,31 @@ select constructor(
PThresh(
"thresh",
Terminal<TPk, TPKh>.NewThresh,
() => TerminalDSLParser.Select(t => Miniscript<TPk, TPKh>.FromAst(t)));
() => TerminalDSLParser().Select(t => Miniscript<TPk, TPKh>.FromAst(t)));

private static Parser<char, Terminal<TPk, TPKh>> PTerminalThreshM =
PThresh("thresh_m", Terminal<TPk, TPKh>.NewThreshM,
() => (from pk in ExprP("pk").Then(s => TryParseMiniscriptKey(s))
select pk));

private static readonly Parser<char, Terminal<TPk, TPKh>> TerminalDSLParser =
// ------ leafs ------
Parse.Ref(() => PTerminalPk)
.Or(Parse.Ref(() => PTerminalPkH))
.Or(Parse.Ref(() => PTerminalAfter))
.Or(Parse.Ref(() => PTerminalOlder))
.Or(Parse.Ref(() => PTerminalSha256))
.Or(Parse.Ref(() => PTerminalHash256))
.Or(Parse.Ref(() => PTerminalRipemd160))
.Or(Parse.Ref(() => PTerminalHash160))
// ------- wrappers --------
.Or(PWrapper('a', Terminal<TPk, TPKh>.NewAlt))
.Or(PWrapper('s', Terminal<TPk, TPKh>.NewSwap))
private static readonly Parser<char, Terminal<TPk, TPKh>> PWrappers =
PWrapper('a', Terminal<TPk, TPKh>.NewAlt)
.Or(PWrapper('c', Terminal<TPk, TPKh>.NewCheck))
.Or(PWrapper('s', Terminal<TPk, TPKh>.NewSwap))
.Or(PWrapper('d', Terminal<TPk, TPKh>.NewDupIf))
.Or(PWrapper('v', Terminal<TPk, TPKh>.NewVerify))
.Or(PWrapper('j', Terminal<TPk, TPKh>.NewZeroNotEqual))
.Or(PWrapper('j', Terminal<TPk, TPKh>.NewZeroNotEqual));

private static Parser<char, Terminal<TPk, TPKh>> PNonWrappers() =>
// ------ leafs ------
PTerminalPk
.Or(PTerminalPkH)
.Or(PTerminalAfter)
.Or(PTerminalOlder)
.Or(PTerminalSha256)
.Or(PTerminalHash256)
.Or(PTerminalRipemd160)
.Or(PTerminalHash160)
// ------- Conjunctions -----
.Or(PBinary("and_v", Terminal<TPk, TPKh>.NewAndV))
.Or(PBinary("and_b", Terminal<TPk, TPKh>.NewAndB))
Expand All @@ -118,8 +123,12 @@ select constructor(
// ------- Thresholds ------
.Or(Parse.Ref(() => PTerminalThresh))
.Or(Parse.Ref(() => PTerminalThreshM));
private static Parser<char, Terminal<TPk, TPKh>> TerminalDSLParser() =>
Parse.Ref(() => PWrappers)
.Or(PNonWrappers());
// ------- wrappers --------

public static Terminal<TPk, TPKh> ParseTerminal(string input)
=> Parse.Ref(() => TerminalDSLParser).Parse(input);
=> TerminalDSLParser().Parse(input);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,6 @@ from x in Parse.CharExcept(')').Many().Text()
from rightB in Parse.Char(')').Token()
select x;

private static string[] SafeSplit(string s)
{
var parenthCount = 0;
var items = new List<string>();
var charSoFar = new List<char>();
var length = s.Length;
for (int i = 0; i < length; i++)
{
var c = s[i];
if (c == '(')
{
parenthCount++;
charSoFar.Add(c);
}
else if (c == ')')
{
parenthCount--;
charSoFar.Add(c);
}
else if (parenthCount != 0)
{
charSoFar.Add(c);
}

if (parenthCount == 0)
{
if (i == length - 1)
{
charSoFar.Add(c);
}
if (c == ',' || i == length - 1)
{
var charsCopy = new List<char>(charSoFar);
charSoFar = new List<char>();
var item = new String(charsCopy.ToArray()).Trim();
items.Add(item);
}
else
{
charSoFar.Add(c);
}
}
}
return items.ToArray();
}

internal static Parser<char, T> TryConvert<T>(string str, Func<string, T> converter)
{
return i =>
Expand Down
16 changes: 8 additions & 8 deletions NBitcoin/Scripting/Miniscript/Types/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ internal static T TypeCheck(Terminal<TPk, TPKh> fragment)

private static T TypeCheckCore(Terminal<TPk, TPKh> fragment,Func<int, T> child)
{
if (fragment is null)
throw new ArgumentNullException(nameof(fragment));

T GetChild(Terminal<TPk, TPKh> sub, int n)
{
try
{
return child(n);
}
catch
{
return TypeCheck(sub, _ => null);
}
var r = child(n);
if (r is null)
return TypeCheck(sub, _ => null);
return r;
}

switch (fragment.Tag)
{
case Terminal<TPk, TPKh>.Tags.True:
Expand Down

0 comments on commit a5dd29b

Please sign in to comment.