mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
[engine] kill Daml withAuthority / LF WITH_AUTHORITY (#16548)
This commit is contained in:
parent
e1a96bc543
commit
ac68bdf416
@ -301,9 +301,6 @@ data BuiltinExpr
|
||||
| BEFoldr -- :: ∀a b. (a -> b -> b) -> b -> List a -> b
|
||||
| BEEqualList -- :: ∀a. (a -> a -> Bool) -> List a -> List a -> Bool
|
||||
|
||||
-- Authority operations
|
||||
| BEWithAuthority -- :: ∀ a. List Party -> Update a -> Update a
|
||||
|
||||
-- Map operations
|
||||
| BETextMapEmpty -- :: ∀ a. TextMap a
|
||||
| BETextMapInsert -- :: ∀ a. Text -> a -> TextMap a -> TextMap a
|
||||
|
@ -267,7 +267,6 @@ instance Pretty BuiltinExpr where
|
||||
BEExpInt64 -> "EXP_INT64"
|
||||
BEFoldl -> "FOLDL"
|
||||
BEFoldr -> "FOLDR"
|
||||
BEWithAuthority -> "WITH_AUTHORITY"
|
||||
BETextMapEmpty -> "TEXTMAP_EMPTY"
|
||||
BETextMapInsert -> "TEXTMAP_INSERT"
|
||||
BETextMapLookup -> "TEXTMAP_LOOKUP"
|
||||
|
@ -476,7 +476,6 @@ decodeBuiltinFunction = \case
|
||||
|
||||
LF1.BuiltinFunctionFOLDL -> pure BEFoldl
|
||||
LF1.BuiltinFunctionFOLDR -> pure BEFoldr
|
||||
LF1.BuiltinFunctionWITH_AUTHORITY -> pure BEWithAuthority
|
||||
LF1.BuiltinFunctionEQUAL_LIST -> pure BEEqualList
|
||||
LF1.BuiltinFunctionAPPEND_TEXT -> pure BEAppendText
|
||||
|
||||
|
@ -516,7 +516,6 @@ encodeBuiltinExpr = \case
|
||||
|
||||
BEFoldl -> builtin P.BuiltinFunctionFOLDL
|
||||
BEFoldr -> builtin P.BuiltinFunctionFOLDR
|
||||
BEWithAuthority -> builtin P.BuiltinFunctionWITH_AUTHORITY
|
||||
BEEqualList -> builtin P.BuiltinFunctionEQUAL_LIST
|
||||
BEExplodeText -> builtin P.BuiltinFunctionEXPLODE_TEXT
|
||||
BEAppendText -> builtin P.BuiltinFunctionAPPEND_TEXT
|
||||
|
@ -137,7 +137,6 @@ safetyStep = \case
|
||||
BEExpInt64 -> Safe 1
|
||||
BEFoldl -> Safe 2
|
||||
BEFoldr -> Safe 2
|
||||
BEWithAuthority -> Safe 2 -- not reachable; so "undefined" would suffice
|
||||
BETextMapEmpty -> Safe 0
|
||||
BETextMapInsert -> Safe 3
|
||||
BETextMapLookup -> Safe 2
|
||||
|
@ -278,12 +278,6 @@ typeOfBuiltin = \case
|
||||
BEFoldr -> pure $ TForall (alpha, KStar) $ TForall (beta, KStar) $
|
||||
(tAlpha :-> tBeta :-> tBeta) :-> tBeta :-> TList tAlpha :-> tBeta
|
||||
|
||||
BEWithAuthority ->
|
||||
pure $ TForall (alpha, KStar) $
|
||||
TList TParty :->
|
||||
TUpdate tAlpha :->
|
||||
TUpdate tAlpha
|
||||
|
||||
BETextMapEmpty -> pure $ TForall (alpha, KStar) $ TTextMap tAlpha
|
||||
BETextMapInsert -> pure $ TForall (alpha, KStar) $ TText :-> tAlpha :-> TTextMap tAlpha :-> TTextMap tAlpha
|
||||
BETextMapLookup -> pure $ TForall (alpha, KStar) $ TText :-> TTextMap tAlpha :-> TOptional tAlpha
|
||||
|
@ -88,10 +88,6 @@ convertPrim _ "BEFoldl" ((b1 :-> a1 :-> b2) :-> b3 :-> TList a2 :-> b4) | a1 ==
|
||||
convertPrim _ "BEFoldr" ((a1 :-> b1 :-> b2) :-> b3 :-> TList a2 :-> b4) | a1 == a2, b1 == b2, b2 == b3, b3 == b4 =
|
||||
pure $ EBuiltin BEFoldr `ETyApp` a1 `ETyApp` b1
|
||||
|
||||
-- Authority operations
|
||||
convertPrim _ "BEWithAuthority" (TList TParty :-> TUpdate a1 :-> TUpdate a2) | a1 == a2 =
|
||||
pure $ EBuiltin BEWithAuthority `ETyApp` a1
|
||||
|
||||
-- Error
|
||||
convertPrim _ "BEError" (TText :-> t2) =
|
||||
pure $ ETyApp (EBuiltin BEError) t2
|
||||
|
@ -48,10 +48,6 @@ module DA.Internal.LF
|
||||
, AnyException
|
||||
#endif
|
||||
|
||||
#ifdef DAML_WITH_AUTHORITY
|
||||
, withAuthorityOf
|
||||
#endif
|
||||
|
||||
) where
|
||||
|
||||
import GHC.Stack.Types (HasCallStack)
|
||||
@ -276,11 +272,3 @@ instance Ord TypeRep where
|
||||
data AnyException = AnyException Opaque
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DAML_WITH_AUTHORITY
|
||||
|
||||
-- | Authority operations.
|
||||
withAuthorityOf : [Party] -> Update a -> Update a
|
||||
withAuthorityOf = primitive @"BEWithAuthority"
|
||||
|
||||
#endif
|
||||
|
@ -29,3 +29,6 @@ template ProposeConsortiumAuthority
|
||||
withAuthorityOf accepted $ do
|
||||
withAuthorityOf [consortiumParty] $ do
|
||||
create HasConsortiumAutority with consortiumParty
|
||||
|
||||
withAuthorityOf : [Party] -> Update a -> Update a
|
||||
withAuthorityOf _ u = u -- TODO #15882 -- require rework
|
||||
|
@ -571,9 +571,7 @@ enum BuiltinFunction {
|
||||
|
||||
TYPE_REP_TYCON_NAME = 148; // *Available in versions >= 1.dev*
|
||||
|
||||
WITH_AUTHORITY = 149; // *Available in versions >= 1.dev*
|
||||
|
||||
// Next id is 150.
|
||||
// Next id is 149.
|
||||
|
||||
// EXPERIMENTAL TEXT PRIMITIVES -- these do not yet have stable numbers.
|
||||
TEXT_TO_UPPER = 9901; // *Available in versions >= 1.dev*
|
||||
|
@ -2099,7 +2099,6 @@ private[archive] object DecodeV1 {
|
||||
BuiltinFunctionInfo(NUMERIC_TO_INT64, BNumericToInt64, minVersion = numeric),
|
||||
BuiltinFunctionInfo(FOLDL, BFoldl),
|
||||
BuiltinFunctionInfo(FOLDR, BFoldr),
|
||||
BuiltinFunctionInfo(WITH_AUTHORITY, BWithAuthority),
|
||||
BuiltinFunctionInfo(TEXTMAP_EMPTY, BTextMapEmpty),
|
||||
BuiltinFunctionInfo(TEXTMAP_INSERT, BTextMapInsert),
|
||||
BuiltinFunctionInfo(TEXTMAP_LOOKUP, BTextMapLookup),
|
||||
|
@ -2509,8 +2509,8 @@ class EngineTest
|
||||
case Right((_, _)) =>
|
||||
}
|
||||
}
|
||||
|
||||
"authority required; not granted" in {
|
||||
/*
|
||||
"authority required; not granted" in { // TODO #15882 -- rework required
|
||||
inside(run(mkCommand(party1 = alice, party2 = bob), grantNeedAuthority = false)) {
|
||||
case Left(
|
||||
Interpretation(
|
||||
@ -2523,11 +2523,12 @@ class EngineTest
|
||||
}
|
||||
}
|
||||
|
||||
"authority required; granted" in {
|
||||
"authority required; granted" in { // TODO #15882 -- rework required
|
||||
inside(run(mkCommand(party1 = alice, party2 = bob), grantNeedAuthority = true)) {
|
||||
case Right((_, _)) =>
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,9 +472,6 @@ private[lf] final class PhaseOne(
|
||||
case BFoldr => SBFoldr
|
||||
case BEqualList => SBEqualList
|
||||
|
||||
// Authority functions
|
||||
case BWithAuthority => SBWithAuthority
|
||||
|
||||
// Errors
|
||||
case BError => SBUserError
|
||||
|
||||
|
@ -1,559 +0,0 @@
|
||||
// Copyright (c) 2023 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
package speedy
|
||||
|
||||
import com.daml.lf.data.FrontStack
|
||||
import com.daml.lf.data.ImmArray
|
||||
import com.daml.lf.data.Ref.Party
|
||||
import com.daml.lf.interpretation.Error.FailedAuthorization
|
||||
import com.daml.lf.ledger.FailedAuthorization.CreateMissingAuthorization
|
||||
import com.daml.lf.speedy.SError.SError
|
||||
import com.daml.lf.speedy.SExpr.SEApp
|
||||
import com.daml.lf.speedy.SValue.{SList, SParty}
|
||||
import com.daml.lf.testing.parser.Implicits._
|
||||
import com.daml.lf.transaction.Node
|
||||
import com.daml.lf.transaction.NodeId
|
||||
import com.daml.lf.transaction.SubmittedTransaction
|
||||
import com.daml.lf.value.Value.{ValueRecord, ValueParty}
|
||||
|
||||
import org.scalatest.Inside
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import org.scalatest.matchers.should.Matchers._
|
||||
|
||||
class WithAuthorityTest extends AnyFreeSpec with Inside {
|
||||
|
||||
val a = Party.assertFromString("Alice")
|
||||
val b = Party.assertFromString("Bob")
|
||||
val c = Party.assertFromString("Charlie")
|
||||
|
||||
import WithAuthorityTest._
|
||||
import SpeedyTestLib.AuthRequest
|
||||
|
||||
"Single" - {
|
||||
|
||||
"single (auth changed): A->{B}->A [FAIL]" in {
|
||||
inside(makeSingle(committers = Set(a), required = Set(b), signed = a)) { case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(b)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"single (auth changed): A->{B}->B [OK]" in {
|
||||
inside(makeSingle(committers = Set(a), required = Set(b), signed = b)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b), List(Create(b))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a), requesting = Set(b)))
|
||||
}
|
||||
}
|
||||
"single (auth restricted/extended) {A,B}->{B,C}->A [FAIL]" in {
|
||||
inside(makeSingle(committers = Set(a, b), required = Set(b, c), signed = a)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(b, c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"single (auth restricted/extended) {A,B}->{B,C}->B [OK]" in {
|
||||
inside(makeSingle(committers = Set(a, b), required = Set(b, c), signed = b)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b, c), List(Create(b))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a, b), requesting = Set(c)))
|
||||
}
|
||||
}
|
||||
"single (auth restricted/extended) {A,B}->{B,C}->C [OK]" in {
|
||||
inside(makeSingle(committers = Set(a, b), required = Set(b, c), signed = c)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b, c), List(Create(c))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a, b), requesting = Set(c)))
|
||||
}
|
||||
}
|
||||
"single (auth unchanged) A->{A}->A [OK; no auth-node]" in {
|
||||
inside(makeSingle(committers = Set(a), required = Set(a), signed = a)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Create(a))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List()
|
||||
}
|
||||
}
|
||||
"single (auth restricted) {A,B}->{B}->B [OK; no auth-node]" in {
|
||||
inside(makeSingle(committers = Set(a, b), required = Set(b), signed = b)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Create(b))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List()
|
||||
}
|
||||
}
|
||||
"single (auth restricted) {A,B}->{B}->A [FAIL]" in {
|
||||
inside(makeSingle(committers = Set(a, b), required = Set(b), signed = a)) { case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(b)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Sequence1" - {
|
||||
|
||||
"sequence1: A-> ( {B}->B ; ->A ) [OK]" in {
|
||||
inside(
|
||||
makeSequence1(
|
||||
committers = Set(a),
|
||||
required = Set(b),
|
||||
signed1 = b,
|
||||
signed2 = a,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List[Shape](Authority(Set(b), List(Create(b))), Create(a))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a), requesting = Set(b)))
|
||||
}
|
||||
}
|
||||
"sequence1: A-> ( {B}->B ; ->B ) [FAIL]" in {
|
||||
inside(
|
||||
makeSequence1(
|
||||
committers = Set(a),
|
||||
required = Set(b),
|
||||
signed1 = b,
|
||||
signed2 = b,
|
||||
)
|
||||
) { case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(a)
|
||||
cma.requiredParties shouldBe Set(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"sequence1: A-> ( {A}->A ; ->A ) [OK; no auth-node]" in {
|
||||
inside(
|
||||
makeSequence1(
|
||||
committers = Set(a),
|
||||
required = Set(a),
|
||||
signed1 = a,
|
||||
signed2 = a,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List[Shape](Create(a), Create(a))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List()
|
||||
}
|
||||
}
|
||||
"sequence1: {A,B}-> ( {B}->B ; ->A ) [OK; no auth-node]" in {
|
||||
inside(
|
||||
makeSequence1(
|
||||
committers = Set(a, b),
|
||||
required = Set(b),
|
||||
signed1 = b,
|
||||
signed2 = a,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List[Shape](Create(b), Create(a))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List()
|
||||
}
|
||||
}
|
||||
"sequence1: {A,B}-> ( {B}->B ; ->B ) [OK; no auth-node]" in {
|
||||
inside(
|
||||
makeSequence1(
|
||||
committers = Set(a, b),
|
||||
required = Set(b),
|
||||
signed1 = b,
|
||||
signed2 = b,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List[Shape](Create(b), Create(b))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"Sequence2" - {
|
||||
|
||||
"sequence2: A-> ( {B}->B ; {C}->C ) [OK; 2 auth nodes]" in {
|
||||
inside(
|
||||
makeSequence2(
|
||||
committers = Set(a),
|
||||
required1 = Set(b),
|
||||
signed1 = b,
|
||||
required2 = Set(c),
|
||||
signed2 = c,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b), List(Create(b))), Authority(Set(c), List(Create(c))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
AuthRequest(holding = Set(a), requesting = Set(c)),
|
||||
)
|
||||
}
|
||||
}
|
||||
"sequence2: A-> ( {B}->B ; {B}->B ) [OK; 2 auth nodes]" in {
|
||||
inside(
|
||||
makeSequence2(
|
||||
committers = Set(a),
|
||||
required1 = Set(b),
|
||||
signed1 = b,
|
||||
required2 = Set(b),
|
||||
signed2 = b,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b), List(Create(b))), Authority(Set(b), List(Create(b))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
)
|
||||
}
|
||||
}
|
||||
"sequence2: A-> ( {B}->B ; {A}->A ) [OK; only 1 auth node]" in {
|
||||
inside(
|
||||
makeSequence2(
|
||||
committers = Set(a),
|
||||
required1 = Set(b),
|
||||
signed1 = b,
|
||||
required2 = Set(a),
|
||||
signed2 = a,
|
||||
)
|
||||
) { case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List[Shape](Authority(Set(b), List(Create(b))), Create(a))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a), requesting = Set(b)))
|
||||
}
|
||||
}
|
||||
"sequence2: A-> ( {B}->B ; {C}->A ) [FAIL]" in {
|
||||
inside(
|
||||
makeSequence2(
|
||||
committers = Set(a),
|
||||
required1 = Set(b),
|
||||
signed1 = b,
|
||||
required2 = Set(c),
|
||||
signed2 = a,
|
||||
)
|
||||
) { case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"sequence2: A-> ( {B}->B ; {C}->B ) [FAIL]" in {
|
||||
inside(
|
||||
makeSequence2(
|
||||
committers = Set(a),
|
||||
required1 = Set(b),
|
||||
signed1 = b,
|
||||
required2 = Set(c),
|
||||
signed2 = b,
|
||||
)
|
||||
) { case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Nested" - {
|
||||
|
||||
"nested: A->{B}->{C}->C [OK]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(b), inner = Set(c), signed = c)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(b), List(Authority(Set(c), List(Create(c))))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
AuthRequest(holding = Set(b), requesting = Set(c)),
|
||||
)
|
||||
}
|
||||
}
|
||||
"nested: A->{B}->{C}->A [FAIL]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(b), inner = Set(c), signed = a)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"nested: A->{B}->{C}->B [FAIL]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(b), inner = Set(c), signed = b)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"nested: A->{A}->{C}->C [OK; 1 auth-node]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(a), inner = Set(c), signed = c)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(c), List(Create(c))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a), requesting = Set(c)))
|
||||
}
|
||||
}
|
||||
"nested: A->{A}->{C}->A [FAIL]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(a), inner = Set(c), signed = a)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"nested: A->{C}->{C}->C [OK; 1 auth-node]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(c), inner = Set(c), signed = c)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(c), List(Create(c))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(AuthRequest(holding = Set(a), requesting = Set(c)))
|
||||
}
|
||||
}
|
||||
"nested: A->{C}->{C}->A [FAIL]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(c), inner = Set(c), signed = a)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"nested: A->{A,B}->{B,C}->C [OK]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(a, b), inner = Set(b, c), signed = c)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(a, b), List(Authority(Set(b, c), List(Create(c))))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
AuthRequest(holding = Set(a, b), requesting = Set(c)),
|
||||
)
|
||||
}
|
||||
}
|
||||
"nested: A->{A,B}->{B,C}->B [OK]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(a, b), inner = Set(b, c), signed = b)) {
|
||||
case Right((tx, ars)) =>
|
||||
val shape = shapeOfTransaction(tx)
|
||||
val expected = List(Authority(Set(a, b), List(Authority(Set(b, c), List(Create(b))))))
|
||||
shape shouldBe expected
|
||||
ars shouldBe List(
|
||||
AuthRequest(holding = Set(a), requesting = Set(b)),
|
||||
AuthRequest(holding = Set(a, b), requesting = Set(c)),
|
||||
)
|
||||
}
|
||||
}
|
||||
"nested: A->{A,B}->{B,C}->A [FAIL]" in {
|
||||
inside(makeNested(committers = Set(a), outer = Set(a, b), inner = Set(b, c), signed = a)) {
|
||||
case Left(err) =>
|
||||
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
|
||||
inside(why) { case cma: CreateMissingAuthorization =>
|
||||
cma.authorizingParties shouldBe Set(b, c)
|
||||
cma.requiredParties shouldBe Set(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO #15882 -- test interaction between Authority and Exercise/Rollback nodes
|
||||
|
||||
}
|
||||
|
||||
object WithAuthorityTest {
|
||||
|
||||
import SpeedyTestLib.loggingContext
|
||||
import SpeedyTestLib.AuthRequest
|
||||
|
||||
val transactionSeed = crypto.Hash.hashPrivateKey("WithAuthorityTest.scala")
|
||||
|
||||
val pkgs: PureCompiledPackages = SpeedyTestLib.typeAndCompile(p"""
|
||||
module M {
|
||||
|
||||
record @serializable T1 = { signed: Party, info: Int64 } ;
|
||||
template (record : T1) = {
|
||||
precondition True;
|
||||
signatories Cons @Party [M:T1 {signed} record] (Nil @Party);
|
||||
observers Nil @Party;
|
||||
agreement "Agreement";
|
||||
};
|
||||
|
||||
val single : List Party -> Party -> Update Unit =
|
||||
\(requested: List Party) -> \(signed: Party) ->
|
||||
WITH_AUTHORITY @Unit requested
|
||||
(ubind x1: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed, info = 100 }
|
||||
in upure @Unit ());
|
||||
|
||||
val nested : List Party -> List Party -> Party -> Update Unit =
|
||||
\(outer: List Party) -> \(inner: List Party) -> \(signed: Party) ->
|
||||
WITH_AUTHORITY @Unit outer
|
||||
(WITH_AUTHORITY @Unit inner
|
||||
(ubind x1: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed, info = 100 }
|
||||
in upure @Unit ()));
|
||||
|
||||
val sequence1 : List Party -> Party -> Party -> Update Unit =
|
||||
\(required1: List Party) -> \(signed1: Party) -> \(signed2: Party) ->
|
||||
ubind
|
||||
u: Unit <-
|
||||
WITH_AUTHORITY @Unit required1
|
||||
(ubind x1: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed1, info = 100 }
|
||||
in upure @Unit ());
|
||||
x2: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed2, info = 100 }
|
||||
in upure @Unit ();
|
||||
|
||||
val sequence2 : List Party -> Party -> List Party -> Party -> Update Unit =
|
||||
\(required1: List Party) -> \(signed1: Party) -> \(required2: List Party) -> \(signed2: Party) ->
|
||||
ubind
|
||||
u: Unit <-
|
||||
WITH_AUTHORITY @Unit required1
|
||||
(ubind x1: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed1, info = 100 }
|
||||
in upure @Unit ());
|
||||
u: Unit <-
|
||||
WITH_AUTHORITY @Unit required2
|
||||
(ubind x2: ContractId M:T1 <- create @M:T1 M:T1 { signed = signed2, info = 100 }
|
||||
in upure @Unit ())
|
||||
in upure @Unit ();
|
||||
}
|
||||
""")
|
||||
|
||||
def makeSetPartyValue(set: Set[Party]): SValue = {
|
||||
SList(FrontStack(set.toList.map(SParty(_)): _*))
|
||||
}
|
||||
|
||||
type Success = (SubmittedTransaction, List[AuthRequest])
|
||||
|
||||
def makeSingle(
|
||||
committers: Set[Party],
|
||||
required: Set[Party],
|
||||
signed: Party,
|
||||
): Either[SError, Success] = {
|
||||
val requiredV = makeSetPartyValue(required)
|
||||
val signedV = SParty(signed)
|
||||
val example = SEApp(pkgs.compiler.unsafeCompile(e"M:single"), Array(requiredV, signedV))
|
||||
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
|
||||
SpeedyTestLib.buildTransactionCollectAuthRequests(machine)
|
||||
}
|
||||
|
||||
def makeSequence1(
|
||||
committers: Set[Party],
|
||||
required: Set[Party],
|
||||
signed1: Party,
|
||||
signed2: Party,
|
||||
): Either[SError, Success] = {
|
||||
val requiredV = makeSetPartyValue(required)
|
||||
val signed1V = SParty(signed1)
|
||||
val signed2V = SParty(signed2)
|
||||
val example = SEApp(
|
||||
pkgs.compiler.unsafeCompile(e"M:sequence1"),
|
||||
Array(requiredV, signed1V, signed2V),
|
||||
)
|
||||
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
|
||||
SpeedyTestLib.buildTransactionCollectAuthRequests(machine)
|
||||
}
|
||||
|
||||
def makeSequence2(
|
||||
committers: Set[Party],
|
||||
required1: Set[Party],
|
||||
signed1: Party,
|
||||
required2: Set[Party],
|
||||
signed2: Party,
|
||||
): Either[SError, Success] = {
|
||||
val required1V = makeSetPartyValue(required1)
|
||||
val signed1V = SParty(signed1)
|
||||
val required2V = makeSetPartyValue(required2)
|
||||
val signed2V = SParty(signed2)
|
||||
val example = SEApp(
|
||||
pkgs.compiler.unsafeCompile(e"M:sequence2"),
|
||||
Array(required1V, signed1V, required2V, signed2V),
|
||||
)
|
||||
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
|
||||
SpeedyTestLib.buildTransactionCollectAuthRequests(machine)
|
||||
}
|
||||
|
||||
def makeNested(
|
||||
committers: Set[Party],
|
||||
outer: Set[Party],
|
||||
inner: Set[Party],
|
||||
signed: Party,
|
||||
): Either[SError, Success] = {
|
||||
val outerV = makeSetPartyValue(outer)
|
||||
val innerV = makeSetPartyValue(inner)
|
||||
val signedV = SParty(signed)
|
||||
val example = SEApp(pkgs.compiler.unsafeCompile(e"M:nested"), Array(outerV, innerV, signedV))
|
||||
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
|
||||
SpeedyTestLib.buildTransactionCollectAuthRequests(machine)
|
||||
}
|
||||
|
||||
sealed trait Shape // minimal transaction tree, for purposes of writing test expectation
|
||||
final case class Create(signed: Party) extends Shape
|
||||
final case class Exercise(x: List[Shape]) extends Shape
|
||||
final case class Rollback(x: List[Shape]) extends Shape
|
||||
final case class Authority(obtained: Set[Party], x: List[Shape]) extends Shape
|
||||
|
||||
private def shapeOfTransaction(tx: SubmittedTransaction): List[Shape] = {
|
||||
def trees(nid: NodeId): List[Shape] = {
|
||||
tx.nodes(nid) match {
|
||||
case create: Node.Create =>
|
||||
create.arg match {
|
||||
case ValueRecord(_, ImmArray((None, ValueParty(signed)), _)) =>
|
||||
List(Create(signed))
|
||||
case _ =>
|
||||
sys.error(s"unexpected create.arg: ${create.arg}")
|
||||
}
|
||||
case _: Node.LeafOnlyAction =>
|
||||
Nil
|
||||
case node: Node.Exercise =>
|
||||
List(Exercise(node.children.toList.flatMap(nid => trees(nid))))
|
||||
case node: Node.Rollback =>
|
||||
List(Rollback(node.children.toList.flatMap(nid => trees(nid))))
|
||||
case node: Node.Authority =>
|
||||
List(Authority(node.obtained, node.children.toList.flatMap(nid => trees(nid))))
|
||||
}
|
||||
}
|
||||
tx.roots.toList.flatMap(nid => trees(nid))
|
||||
}
|
||||
}
|
@ -457,10 +457,6 @@ object Ast {
|
||||
final case object BFoldl extends BuiltinFunction // : ∀a b. (b → a → b) → b → List a → b
|
||||
final case object BFoldr extends BuiltinFunction // : ∀a b. (a → b → b) → b → List a → b
|
||||
|
||||
// Authority
|
||||
final case object BWithAuthority
|
||||
extends BuiltinFunction // : ∀ a. List Party → Update a → Update a
|
||||
|
||||
// Maps
|
||||
final case object BTextMapEmpty extends BuiltinFunction // : ∀ a. TextMap a
|
||||
final case object BTextMapInsert
|
||||
|
@ -338,7 +338,6 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) {
|
||||
"UNIX_MICROSECONDS_TO_TIMESTAMP" -> BUnixMicrosecondsToTimestamp,
|
||||
"FOLDL" -> BFoldl,
|
||||
"FOLDR" -> BFoldr,
|
||||
"WITH_AUTHORITY" -> BWithAuthority,
|
||||
"TEXTMAP_EMPTY" -> BTextMapEmpty,
|
||||
"TEXTMAP_INSERT" -> BTextMapInsert,
|
||||
"TEXTMAP_LOOKUP" -> BTextMapLookup,
|
||||
|
@ -209,7 +209,6 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
|
||||
"UNIX_MICROSECONDS_TO_TIMESTAMP" -> BUnixMicrosecondsToTimestamp,
|
||||
"FOLDL" -> BFoldl,
|
||||
"FOLDR" -> BFoldr,
|
||||
"WITH_AUTHORITY" -> BWithAuthority,
|
||||
"EXPLODE_TEXT" -> BExplodeText,
|
||||
"IMPLODE_TEXT" -> BImplodeText,
|
||||
"APPEND_TEXT" -> BAppendText,
|
||||
|
@ -4557,15 +4557,6 @@ List functions
|
||||
predicate give as first argument.
|
||||
|
||||
|
||||
Authority functions
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ``WITH_AUTHORITY : ∀ (α : ⋆) . 'List' 'Party' → 'Update' α → 'Update' α``
|
||||
|
||||
Request authorization from the ledger for the scope of an update operation.
|
||||
|
||||
[*Available in versions >= 1.dev*]
|
||||
|
||||
Text map functions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -22,3 +22,7 @@ template T
|
||||
withAuthorityOf [party2] $ do
|
||||
create (HaveAuthority party2)
|
||||
pure ()
|
||||
|
||||
|
||||
withAuthorityOf : [Party] -> Update a -> Update a
|
||||
withAuthorityOf _ u = u -- TODO #15882 -- require rework
|
||||
|
@ -137,12 +137,6 @@ private[validation] object Typing {
|
||||
alpha.name -> KStar,
|
||||
TForall(beta.name -> KStar, (alpha ->: beta ->: beta) ->: beta ->: TList(alpha) ->: beta),
|
||||
),
|
||||
// Authority
|
||||
BWithAuthority ->
|
||||
TForall(
|
||||
alpha.name -> KStar,
|
||||
TList(TParty) ->: TUpdate(alpha) ->: TUpdate(alpha),
|
||||
),
|
||||
// Maps
|
||||
BTextMapEmpty ->
|
||||
TForall(
|
||||
|
@ -32,6 +32,8 @@ template ProposeConsortiumAuthority
|
||||
withAuthorityOf [consortiumParty] $ do
|
||||
create HasConsortiumAutority with consortiumParty
|
||||
|
||||
withAuthorityOf : [Party] -> Update a -> Update a
|
||||
withAuthorityOf _ u = u -- TODO #15882 -- require rework
|
||||
|
||||
test : Script ()
|
||||
test = do
|
||||
@ -46,7 +48,8 @@ test = do
|
||||
proposer = alice
|
||||
accepted = []
|
||||
obs = [bob,charlie]
|
||||
consortiumParty = org
|
||||
--consortiumParty = org -- TODO #15882 -- require rework
|
||||
consortiumParty = alice
|
||||
|
||||
prop <- submit bob do exerciseCmd prop Accept with who = bob
|
||||
prop <- submit charlie do exerciseCmd prop Accept with who = charlie
|
||||
|
Loading…
Reference in New Issue
Block a user