Merge remote-tracking branch 'origin/main' into dylan-lf-15-minimal

This commit is contained in:
Dylan Thinnes 2022-08-23 10:27:21 +01:00
commit 0d5f167fc6
32 changed files with 569 additions and 353 deletions

53
NOTICES
View File

@ -22,11 +22,8 @@ Components:
@babel/code-frame 7.12.11 : MIT License
@babel/code-frame 7.12.13 : MIT License
@babel/code-frame 7.18.6 : MIT License
@babel/compat-data 7.18.8 : MIT License
@babel/core 7.18.10 : MIT License
@babel/generator 7.14.1 : MIT License
@babel/generator 7.16.0 : MIT License
@babel/generator 7.18.12 : MIT License
@babel/helper-annotate-as-pure 7.12.13 : MIT License
@babel/helper-compilation-targets 7.18.9 : MIT License
@babel/helper-environment-visitor 7.18.9 : MIT License
@ -51,7 +48,6 @@ Components:
@babel/highlight 7.18.6 : MIT License
@babel/parser 7.14.1 : MIT License
@babel/parser 7.17.0 : MIT License
@babel/parser 7.18.11 : MIT License
@babel/plugin-syntax-async-generators 7.8.4 : MIT License
@babel/plugin-syntax-bigint 7.8.3 : MIT License
@babel/plugin-syntax-class-properties 7.12.13 : MIT License
@ -70,11 +66,9 @@ Components:
@babel/template 7.12.13 : MIT License
@babel/template 7.18.10 : MIT License
@babel/traverse 7.14.0 : MIT License
@babel/traverse 7.18.11 : MIT License
@babel/types 7.14.1 : MIT License
@babel/types 7.16.0 : MIT License
@babel/types 7.17.0 : MIT License
@babel/types 7.18.10 : MIT License
@bazel/hide-bazel-files 1.6.0 : Apache License 2.0
@bazel/hide-bazel-files 1.7.0 : Apache License 2.0
@bazel/typescript 4.6.1 : Apache License 2.0
@ -484,7 +478,6 @@ camelcase 6.3.0 : MIT License
camelcase-keys 2.1.0 : MIT License
camelize 1.0.0 : MIT License
caniuse-lite 1.0.30001260 : Creative Commons Attribution 4.0
caniuse-lite 1.0.30001380 : Creative Commons Attribution 4.0
Cardinal 2.1.1 : MIT License
case-sensitive-paths-webpack-plugin 2.4.0 : MIT License
Cats core 2.6.1 : MIT License
@ -723,7 +716,6 @@ ekmett/free v5.1.7 : BSD 3-clause "New" or "Revised" License
ekmett/profunctors v5.6.2 : BSD 3-clause "New" or "Revised" License
ekmett/void v0.7.3 : BSD 3-clause "New" or "Revised" License
electron-to-chromium 1.3.850 : ISC License
electron-to-chromium 1.4.225 : ISC License
elegant-spinner 1.0.1 : MIT License
elliptic v6.5.4 : MIT License
emittery v0.8.1 : MIT License
@ -1760,6 +1752,7 @@ qs - QS Querystring 6.9.4 : BSD 3-clause "New" or "Revised" License
qs - QS Querystring v6.7.0 : BSD 3-clause "New" or "Revised" License
qs - QS Querystring v6.9.6 : BSD 3-clause "New" or "Revised" License
querystring-es3 0.2.1 : MIT License
querystringify 2.2.0 : MIT License
queue-microtask 1.2.3 : MIT License
QuickCheck 2.14.2 : BSD 3-clause "New" or "Revised" License
quickcheck-instances 0.3.27 : BSD 3-clause "New" or "Revised" License
@ -2121,7 +2114,6 @@ to-arraybuffer 1.0.1 : MIT License
to-fast-properties 2.0.0 : MIT License
to-regex-range 5.0.1 : MIT License
toidentifier 1.0.0 : MIT License
tough-cookie 4.0.0 : BSD 3-clause "New" or "Revised" License
Toxiproxy Java Client 2.1.3 : Apache License 2.0
tr46 0.0.3 : MIT License
tr46 2.1.0 : MIT License
@ -2184,6 +2176,7 @@ unist-util-visit 2.0.3 : MIT License
unist-util-visit-parents 1.1.2 : MIT License
unist-util-visit-parents 3.1.1 : MIT License
universalify 0.1.2 : MIT License
universalify 0.2.0 : MIT License
universalify 2.0.0 : MIT License
unix-compat 0.5.4 : BSD 3-clause "New" or "Revised" License
unix-time 0.4.7 : BSD 3-clause "New" or "Revised" License
@ -2199,6 +2192,7 @@ uri-encode 1.5.0.7 : BSD 3-clause "New" or "Revised" License
uri-js 4.4.1 : BSD 2-clause "Simplified" License
uri-path 1.0.0 : (MIT License OR Do What The F*ck You Want To Public License)
url-loader 4.1.1 : MIT License
url-parse 1.5.10 : MIT License
urljoin 4.0.1 : MIT License
utf8-string v1.0.2 : BSD 3-clause "New" or "Revised" License
util 0.10.3 : MIT License
@ -5045,37 +5039,6 @@ Redistribution and use in source and binary forms, with or without
---
BSD 3-clause "New" or "Revised" License
(tough-cookie 4.0.0)
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
---
BSD 3-clause "New" or "Revised" License
(Protocol Buffers 3.18.1)
@ -6189,7 +6152,7 @@ POSSIBILITY OF SUCH DAMAGES.
---
Creative Commons Attribution 4.0
(caniuse-lite 1.0.30001260, caniuse-lite 1.0.30001380)
(caniuse-lite 1.0.30001260)
Creative Commons Attribution 4.0
================================
@ -9414,7 +9377,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
---
ISC License
(@apollographql/graphql-language-service-interface 2.0.2, @apollographql/graphql-language-service-parser 2.0.2, @apollographql/graphql-language-service-types 2.0.2, @apollographql/graphql-language-service-utils 2.0.2, @oclif/linewrap 1.0.0, boolbase 1.0.0, electron-to-chromium 1.4.225, http-call 5.3.0, node-glob 7.2.3, node-graceful-fs 4.2.10, node-semver 7.3.7, tty 1.0.1)
(@apollographql/graphql-language-service-interface 2.0.2, @apollographql/graphql-language-service-parser 2.0.2, @apollographql/graphql-language-service-types 2.0.2, @apollographql/graphql-language-service-utils 2.0.2, @oclif/linewrap 1.0.0, boolbase 1.0.0, http-call 5.3.0, node-glob 7.2.3, node-graceful-fs 4.2.10, node-semver 7.3.7, tty 1.0.1)
ISC License (ISCL)
==================
@ -11421,7 +11384,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
---
MIT License
(universalify 0.1.2, universalify 2.0.0)
(universalify 0.1.2, universalify 0.2.0, universalify 2.0.0)
(The MIT License)
@ -19634,7 +19597,7 @@ OTHER DEALINGS IN THE SOFTWARE
---
MIT License
(@babel/code-frame 7.18.6, @babel/compat-data 7.18.8, @babel/core 7.18.10, @babel/generator 7.18.12, @babel/helper-compilation-targets 7.18.9, @babel/helper-environment-visitor 7.18.9, @babel/helper-function-name 7.18.9, @babel/helper-hoist-variables 7.18.6, @babel/helper-module-imports 7.18.6, @babel/helper-module-transforms 7.18.9, @babel/helper-plugin-utils 7.18.9, @babel/helper-simple-access 7.18.6, @babel/helper-split-export-declaration 7.18.6, @babel/helper-string-parser 7.18.10, @babel/helper-validator-identifier 7.18.6, @babel/helper-validator-option 7.18.6, @babel/helpers 7.18.9, @babel/highlight 7.18.6, @babel/parser 7.18.11, @babel/plugin-syntax-typescript 7.18.6, @babel/runtime 7.18.9, @babel/template 7.18.10, @babel/traverse 7.18.11, @babel/types 7.18.10, @emotion/unitless 0.7.5, @graphql-typed-document-node/core 3.1.0, @jest/fake-timers 27.5.1, @jest/source-map 27.5.1, @jest/transform 27.5.1, @jridgewell/gen-mapping 0.1.1, @jridgewell/gen-mapping 0.3.2, @jridgewell/resolve-uri 3.1.0, @jridgewell/set-array 1.1.2, @jridgewell/source-map 0.3.2, @jridgewell/sourcemap-codec 1.4.14, @jridgewell/trace-mapping 0.3.14, @jridgewell/trace-mapping 0.3.15, @oclif/parser 3.8.6, @tootallnate/once 1.1.2, @types/babel__traverse 7.18.0, @types/istanbul-lib-coverage 2.0.4, @types/json5 0.0.29, @types/long 4.0.2, @types/node 18.6.3, @types/prettier 2.7.0, @types/prop-types 15.7.5, @types/react 17.0.48, @types/react 18.0.17, @types/react-test-renderer 18.0.0, @types/tmp 0.0.29, @types/warning 3.0.0, Acorn 8.8.0, acorn-import-assertions 1.7.6, Animal Sniffer Annotations 1.19, apollo-codegen-itajaja 0.38.7, apollo-language-server 1.26.7, Async 2.6.4, Async 3.2.4, babel-plugin-syntax-jsx 6.18.0, better-files 3.8.0, Bouncy Castle 1.70, Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs 1.70, browserify-cache-api 3.0.1, browserify-incremental 3.1.1, browserify-zlib 0.1.4, browserify/resolve 1.22.1, browserslist 4.21.3, cached-path-relative 1.1.0, Cats core 2.6.1, Cats Free 2.6.1, Cats kernel 2.6.1, Cats kernel laws 2.6.1, Cats laws 2.6.1, ci-info 3.3.2, Clone 1.0.4, cookie 0.4.5, csstype 3.1.0, decimal.js 10.4.0, discipline 1.1.5, doobie-core 0.13.4, doobie-free 0.13.4, doobie-hikari 0.13.4, doobie-postgres 0.13.4, einaros/ws 7.5.9, einaros/ws 8.8.1, env-ci 5.4.1, error v7.2.1, fansi_2.13 0.3.0, fast-uuid 0.1, fastparse_2.13 2.3.0, fs2-core 2.5.6, fs2-io 2.5.6, generics-resolver 3.0.3, geny_2.13 0.6.2, getobject 1.0.0, graphql-tag 2.12.6, grunt-legacy-log-utils 2.0.1, grunt-legacy-log-utils 2.1.0, grunt-open v0.2.4, gruntjs 1.4.2, gruntjs 1.4.3, gruntjs 1.5.3, hs-tasty 0.10.2, hs-tasty 1.4.2.1, http-client 0.7.10, https-proxy-agent 5.0.1, indexof 0.0.1, integer-logarithms 1.0.3.1, is-core-module 2.10.0, java-properties 1.0.2, jest-changed-files 27.5.1, jest-circus 27.5.1, jest-get-type 27.5.1, jest-mock-console 1.3.0, jest-resolve 27.5.1, jest-resolve-dependencies 27.5.1, jest-runner 27.5.1, jwks-rsa 0.11.0, jwt 0.11.0, kind-projector 0.13.2, kossnocorp/date-fns 1.30.1, lightning-csv 8.2.3, macros 0.17.0, mockito-scala 1.16.3, mod 0.1.2.2, Modernizr 3.11.8, moment/moment 2.29.4, natural-compare 1.4.0, node-deep-equal 1.1.1, node-mkdirp 0.5.6, node-releases 2.0.6, node-xml2js 0.4.23, nwsapi 2.2.1, os-lib_2.13 0.7.1, parse-path 5.0.0, parser 1.0.0, path-platform 0.11.15, PCollections 2.1.3, pprint_2.13 0.7.1, protocols 2.0.1, psl 1.9.0, React from Facebook 18.2.0, react-shallow-renderer 16.15.0, react-themeable 1.1.0, scalatags 0.9.1, scopt 4.0.0, sfm-util 8.2.3, sjsonnet_2.13 0.3.0, SLF4J API Module 1.7.26, sourcecode 0.2.7, streaming-commons 0.2.2.3, Styled Components 5.3.0, tr46 0.0.3, ts-jest 27.1.5, typed-process 0.2.8.0, typename 1.0.0, typescript-collections 1.3.3, ujson_2.13 1.2.0, update-browserslist-db 1.0.5, upickle-core_2.13 1.2.0, upper-case 2.0.2, wcwidth 1.0.1)
(@babel/code-frame 7.18.6, @babel/helper-compilation-targets 7.18.9, @babel/helper-environment-visitor 7.18.9, @babel/helper-function-name 7.18.9, @babel/helper-hoist-variables 7.18.6, @babel/helper-module-imports 7.18.6, @babel/helper-module-transforms 7.18.9, @babel/helper-plugin-utils 7.18.9, @babel/helper-simple-access 7.18.6, @babel/helper-split-export-declaration 7.18.6, @babel/helper-string-parser 7.18.10, @babel/helper-validator-identifier 7.18.6, @babel/helper-validator-option 7.18.6, @babel/helpers 7.18.9, @babel/highlight 7.18.6, @babel/plugin-syntax-typescript 7.18.6, @babel/runtime 7.18.9, @babel/template 7.18.10, @emotion/unitless 0.7.5, @graphql-typed-document-node/core 3.1.0, @jest/fake-timers 27.5.1, @jest/source-map 27.5.1, @jest/transform 27.5.1, @jridgewell/gen-mapping 0.1.1, @jridgewell/gen-mapping 0.3.2, @jridgewell/resolve-uri 3.1.0, @jridgewell/set-array 1.1.2, @jridgewell/source-map 0.3.2, @jridgewell/sourcemap-codec 1.4.14, @jridgewell/trace-mapping 0.3.14, @jridgewell/trace-mapping 0.3.15, @oclif/parser 3.8.6, @tootallnate/once 1.1.2, @types/babel__traverse 7.18.0, @types/istanbul-lib-coverage 2.0.4, @types/json5 0.0.29, @types/long 4.0.2, @types/node 18.6.3, @types/prettier 2.7.0, @types/prop-types 15.7.5, @types/react 17.0.48, @types/react 18.0.17, @types/react-test-renderer 18.0.0, @types/tmp 0.0.29, @types/warning 3.0.0, Acorn 8.8.0, acorn-import-assertions 1.7.6, Animal Sniffer Annotations 1.19, apollo-codegen-itajaja 0.38.7, apollo-language-server 1.26.7, Async 2.6.4, Async 3.2.4, babel-plugin-syntax-jsx 6.18.0, better-files 3.8.0, Bouncy Castle 1.70, Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs 1.70, browserify-cache-api 3.0.1, browserify-incremental 3.1.1, browserify-zlib 0.1.4, browserify/resolve 1.22.1, browserslist 4.21.3, cached-path-relative 1.1.0, Cats core 2.6.1, Cats Free 2.6.1, Cats kernel 2.6.1, Cats kernel laws 2.6.1, Cats laws 2.6.1, ci-info 3.3.2, Clone 1.0.4, cookie 0.4.5, csstype 3.1.0, decimal.js 10.4.0, discipline 1.1.5, doobie-core 0.13.4, doobie-free 0.13.4, doobie-hikari 0.13.4, doobie-postgres 0.13.4, einaros/ws 7.5.9, einaros/ws 8.8.1, env-ci 5.4.1, error v7.2.1, fansi_2.13 0.3.0, fast-uuid 0.1, fastparse_2.13 2.3.0, fs2-core 2.5.6, fs2-io 2.5.6, generics-resolver 3.0.3, geny_2.13 0.6.2, getobject 1.0.0, graphql-tag 2.12.6, grunt-legacy-log-utils 2.0.1, grunt-legacy-log-utils 2.1.0, grunt-open v0.2.4, gruntjs 1.4.2, gruntjs 1.4.3, gruntjs 1.5.3, hs-tasty 0.10.2, hs-tasty 1.4.2.1, http-client 0.7.10, https-proxy-agent 5.0.1, indexof 0.0.1, integer-logarithms 1.0.3.1, is-core-module 2.10.0, java-properties 1.0.2, jest-changed-files 27.5.1, jest-circus 27.5.1, jest-get-type 27.5.1, jest-mock-console 1.3.0, jest-resolve 27.5.1, jest-resolve-dependencies 27.5.1, jest-runner 27.5.1, jwks-rsa 0.11.0, jwt 0.11.0, kind-projector 0.13.2, kossnocorp/date-fns 1.30.1, lightning-csv 8.2.3, macros 0.17.0, mockito-scala 1.16.3, mod 0.1.2.2, Modernizr 3.11.8, moment/moment 2.29.4, natural-compare 1.4.0, node-deep-equal 1.1.1, node-mkdirp 0.5.6, node-releases 2.0.6, node-xml2js 0.4.23, nwsapi 2.2.1, os-lib_2.13 0.7.1, parse-path 5.0.0, parser 1.0.0, path-platform 0.11.15, PCollections 2.1.3, pprint_2.13 0.7.1, protocols 2.0.1, psl 1.9.0, React from Facebook 18.2.0, react-shallow-renderer 16.15.0, react-themeable 1.1.0, scalatags 0.9.1, scopt 4.0.0, sfm-util 8.2.3, sjsonnet_2.13 0.3.0, SLF4J API Module 1.7.26, sourcecode 0.2.7, streaming-commons 0.2.2.3, Styled Components 5.3.0, tr46 0.0.3, ts-jest 27.1.5, typed-process 0.2.8.0, typename 1.0.0, typescript-collections 1.3.3, ujson_2.13 1.2.0, update-browserslist-db 1.0.5, upickle-core_2.13 1.2.0, upper-case 2.0.2, wcwidth 1.0.1)
The MIT License
===============
@ -22387,7 +22350,7 @@ SOFTWARE
---
MIT License
(requires-port 1.0.0)
(querystringify 2.2.0, requires-port 1.0.0, url-parse 1.5.10)
The MIT License (MIT)

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
canton = {
"sha": "94f8b9294807be25b5f1b973c34ec98c7d2f056f4054e4767144837b7456fcec",
"sha": "ddc3c53251a5d14698fddfc39947ab2238c514ddedcf732d2fc9f3bbac8700de",
"prefix": "canton-open-source-2.4.0-SNAPSHOT",
"url": "https://www.canton.io/releases/canton-open-source-20220819.tar.gz",
"url": "https://www.canton.io/releases/canton-open-source-20220822.tar.gz",
}

View File

@ -76,7 +76,7 @@ class CommandService(
val command = createCommand(input)
val request = submitAndWaitRequest(jwtPayload, input.meta, command, "create")
val et: ET[domain.CreateCommandResponse[lav1.value.Value]] = for {
response <- logResult(Symbol("create"), submitAndWaitForTransaction(jwt, request))
response <- logResult(Symbol("create"), submitAndWaitForTransaction(jwt, request)(lc))
contract <- either(exactlyOneActiveContract(response))
} yield domain.CreateCommandResponse(
contract.contractId,
@ -110,7 +110,7 @@ class CommandService(
val et: ET[ExerciseResponse[lav1.value.Value]] = for {
response <-
logResult(Symbol("exercise"), submitAndWaitForTransactionTree(jwt, request))
logResult(Symbol("exercise"), submitAndWaitForTransactionTree(jwt, request)(lc))
exerciseResult <- either(exerciseResult(response))
contracts <- either(contracts(response))
} yield ExerciseResponse(
@ -137,7 +137,7 @@ class CommandService(
val et: ET[ExerciseResponse[lav1.value.Value]] = for {
response <- logResult(
Symbol("createAndExercise"),
submitAndWaitForTransactionTree(jwt, request),
submitAndWaitForTransactionTree(jwt, request)(lc),
)
exerciseResult <- either(exerciseResult(response))
contracts <- either(contracts(response))

View File

@ -111,7 +111,7 @@ private class ContractsFetch(
// we assume that if the ledger termination is LedgerBegin, then
// `within` will not yield concurrency-relevant results
connectionIOFuture(getTermination(jwt, ledgerId)) flatMap {
connectionIOFuture(getTermination(jwt, ledgerId)(lc)) flatMap {
_.cata(go(initTries, templateIds, _), within(LedgerBegin))
}
}
@ -126,7 +126,7 @@ private class ContractsFetch(
mat: Materializer,
lc: LoggingContextOf[InstanceUUID],
): ConnectionIO[BeginBookmark[Terminates.AtAbsolute]] =
connectionIOFuture(getTermination(jwt, ledgerId)) flatMap {
connectionIOFuture(getTermination(jwt, ledgerId)(lc)) flatMap {
_.cata(
fetchToAbsEnd(FetchContext(jwt, ledgerId, parties), templateIds, _),
fconn.pure(LedgerBegin),
@ -304,7 +304,7 @@ private class ContractsFetch(
transactionFilter(parties, List(templateId)),
_: lav1.ledger_offset.LedgerOffset,
absEnd,
)
)(lc)
// include ACS iff starting at LedgerBegin
val (idses, lastOff) = (startOffset, disableAcs) match {
@ -315,7 +315,7 @@ private class ContractsFetch(
ledgerId,
transactionFilter(parties, List(templateId)),
true,
)
)(lc)
(stepsAndOffset.out0, stepsAndOffset.out1)
case (AbsoluteBookmark(_), _) | (LedgerBegin, true) =>

View File

@ -546,9 +546,9 @@ class ContractsService(
ledgerId: LedgerApiDomain.LedgerId,
parties: domain.PartySet,
templateIds: List[domain.ContractTypeId.Resolved],
): Source[ContractStreamStep.LAV1, NotUsed] = {
)(implicit lc: LoggingContextOf[InstanceUUID]): Source[ContractStreamStep.LAV1, NotUsed] = {
val txnFilter = transactionFilter(parties, templateIds)
getActiveContracts(jwt, ledgerId, txnFilter, true)
getActiveContracts(jwt, ledgerId, txnFilter, true)(lc)
.map { case GetActiveContractsResponse(offset, _, activeContracts) =>
if (activeContracts.nonEmpty) Acs(activeContracts.toVector)
else LiveBegin(AbsoluteBookmark(domain.Offset(offset)))
@ -570,7 +570,7 @@ class ContractsService(
): Source[ContractStreamStep.LAV1, NotUsed] = {
val txnFilter = transactionFilter(parties, templateIds)
def source = getActiveContracts(jwt, ledgerId, txnFilter, true)
def source = getActiveContracts(jwt, ledgerId, txnFilter, true)(lc)
val transactionsSince
: api.ledger_offset.LedgerOffset => Source[api.transaction.Transaction, NotUsed] =
@ -580,7 +580,7 @@ class ContractsService(
txnFilter,
_: api.ledger_offset.LedgerOffset,
terminates,
)
)(lc)
import com.daml.fetchcontracts.AcsTxStreams.{
acsFollowingAndBoundary,

View File

@ -63,6 +63,9 @@ object HttpService {
final case class Error(message: String)
private def isLogLevelEqualOrBelowDebug(logLevel: Option[LogLevel]) =
logLevel.exists(!_.isGreaterOrEqual(LogLevel.INFO))
@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements"))
def start(
startSettings: StartSettings,
@ -152,7 +155,11 @@ object HttpService {
{ case (jwt, ledgerId, byteString) =>
implicit lc =>
LedgerClientJwt
.uploadDar(pkgManagementClient)(jwt, ledgerId, byteString)(lc)
.uploadDar(pkgManagementClient)(ec)(
jwt,
ledgerId,
byteString,
)(lc)
.flatMap(_ => packageService.reload(jwt, ledgerId))
.map(_ => ())
},
@ -160,7 +167,10 @@ object HttpService {
meteringReportService = new MeteringReportService(
{ case (jwt, request) =>
implicit lc => LedgerClientJwt.getMeteringReport(client)(jwt, request)(lc)
implicit lc =>
LedgerClientJwt.getMeteringReport(client)(ec)(jwt, request)(
lc
)
}
)
@ -185,7 +195,7 @@ object HttpService {
healthService,
encoder,
decoder,
logLevel.exists(!_.isGreaterOrEqual(LogLevel.INFO)), // Everything below DEBUG enables this
isLogLevelEqualOrBelowDebug(logLevel),
client.userManagementClient,
client.identityClient,
)

View File

@ -32,12 +32,23 @@ import com.daml.ledger.api.v1.admin.metering_report_service.{
GetMeteringReportRequest,
GetMeteringReportResponse,
}
import com.daml.ledger.client.services.acs.ActiveContractSetClient
import com.daml.ledger.client.services.admin.{
MeteringReportClient,
PackageManagementClient,
PartyManagementClient,
}
import com.daml.ledger.client.services.commands.SynchronousCommandClient
import com.daml.ledger.client.services.pkg.withoutledgerid.PackageClient
import com.daml.ledger.client.services.transactions.withoutledgerid.TransactionClient
import com.google.rpc.{Code, Status}
import io.grpc.protobuf.StatusProto
object LedgerClientJwt {
import Grpc.EFuture, Grpc.Category._
import LedgerClientRequestTimeLogger._
private[this] val logger = ContextualizedLogger.get(getClass)
// there are other error categories of interest if we wish to propagate
@ -47,16 +58,25 @@ object LedgerClientJwt {
(
Jwt,
SubmitAndWaitRequest,
) => EFuture[SubmitError, SubmitAndWaitForTransactionResponse]
) => LoggingContextOf[InstanceUUID with RequestID] => EFuture[
SubmitError,
SubmitAndWaitForTransactionResponse,
]
type SubmitAndWaitForTransactionTree =
(
Jwt,
SubmitAndWaitRequest,
) => EFuture[SubmitError, SubmitAndWaitForTransactionTreeResponse]
) => LoggingContextOf[InstanceUUID with RequestID] => EFuture[
SubmitError,
SubmitAndWaitForTransactionTreeResponse,
]
type GetTermination =
(Jwt, LedgerApiDomain.LedgerId) => Future[Option[Terminates.AtAbsolute]]
(
Jwt,
LedgerApiDomain.LedgerId,
) => LoggingContextOf[InstanceUUID] => Future[Option[Terminates.AtAbsolute]]
type GetActiveContracts =
(
@ -64,7 +84,10 @@ object LedgerClientJwt {
LedgerApiDomain.LedgerId,
TransactionFilter,
Boolean,
) => Source[GetActiveContractsResponse, NotUsed]
) => LoggingContextOf[InstanceUUID] => Source[
GetActiveContractsResponse,
NotUsed,
]
type GetCreatesAndArchivesSince =
(
@ -73,19 +96,27 @@ object LedgerClientJwt {
TransactionFilter,
LedgerOffset,
Terminates,
) => Source[Transaction, NotUsed]
) => LoggingContextOf[InstanceUUID] => Source[Transaction, NotUsed]
type ListKnownParties =
Jwt => EFuture[PermissionDenied, List[api.domain.PartyDetails]]
Jwt => LoggingContextOf[InstanceUUID with RequestID] => EFuture[PermissionDenied, List[
api.domain.PartyDetails
]]
type GetParties =
(
Jwt,
OneAnd[Set, Ref.Party],
) => EFuture[PermissionDenied, List[api.domain.PartyDetails]]
) => LoggingContextOf[InstanceUUID with RequestID] => EFuture[PermissionDenied, List[
api.domain.PartyDetails
]]
type AllocateParty =
(Jwt, Option[Ref.Party], Option[String]) => Future[api.domain.PartyDetails]
(
Jwt,
Option[Ref.Party],
Option[String],
) => LoggingContextOf[InstanceUUID with RequestID] => Future[api.domain.PartyDetails]
type ListPackages =
(Jwt, LedgerApiDomain.LedgerId) => LoggingContextOf[InstanceUUID with RequestID] => Future[
@ -119,34 +150,57 @@ object LedgerClientJwt {
client: DamlLedgerClient
)(implicit ec: EC): SubmitAndWaitForTransaction =
(jwt, req) =>
client.commandServiceClient
.submitAndWaitForTransaction(req, bearer(jwt))
.requireHandling(submitErrors)
implicit lc => {
LedgerClientRequestTimeLogger
.logFuture(SubmitAndWaitForTransactionLog) {
client.commandServiceClient
.submitAndWaitForTransaction(req, bearer(jwt))
}
.requireHandling(submitErrors)
}
def submitAndWaitForTransactionTree(
client: DamlLedgerClient
)(implicit ec: EC): SubmitAndWaitForTransactionTree =
(jwt, req) =>
client.commandServiceClient
.submitAndWaitForTransactionTree(req, bearer(jwt))
.requireHandling(submitErrors)
def getTermination(client: DamlLedgerClient)(implicit ec: EC): GetTermination =
(jwt, ledgerId) =>
client.transactionClient.getLedgerEnd(ledgerId, bearer(jwt)).map {
_.offset flatMap {
_.value match {
case off @ LedgerOffset.Value.Absolute(_) => Some(Terminates.AtAbsolute(off))
case LedgerOffset.Value.Boundary(_) | LedgerOffset.Value.Empty => None // at beginning
implicit lc => {
LedgerClientRequestTimeLogger
.logFuture(SubmitAndWaitForTransactionTreeLog) {
client.commandServiceClient
.submitAndWaitForTransactionTree(req, bearer(jwt))
}
.requireHandling(submitErrors)
}
def getTermination(client: DamlLedgerClient)(implicit
ec: EC
): GetTermination =
(jwt, ledgerId) =>
implicit lc => {
LedgerClientRequestTimeLogger
.logFuture(GetLedgerEndLog) {
client.transactionClient.getLedgerEnd(ledgerId, bearer(jwt))
}
.map {
_.offset flatMap {
_.value match {
case off @ LedgerOffset.Value.Absolute(_) => Some(Terminates.AtAbsolute(off))
case LedgerOffset.Value.Boundary(_) | LedgerOffset.Value.Empty =>
None // at beginning
}
}
}
}
}
def getActiveContracts(client: DamlLedgerClient): GetActiveContracts =
(jwt, ledgerId, filter, verbose) =>
client.activeContractSetClient
.getActiveContracts(filter, ledgerId, verbose, bearer(jwt))
.mapMaterializedValue(_ => NotUsed)
implicit lc => {
LedgerClientRequestTimeLogger
.log(GetActiveContractsLog) {
client.activeContractSetClient
.getActiveContracts(filter, ledgerId, verbose, bearer(jwt))
.mapMaterializedValue(_ => NotUsed)
}
}
sealed abstract class Terminates extends Product with Serializable {
import Terminates._
@ -172,20 +226,25 @@ object LedgerClientJwt {
LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_END))
def getCreatesAndArchivesSince(client: DamlLedgerClient): GetCreatesAndArchivesSince =
(jwt, ledgerId, filter, offset, terminates) => {
val end = terminates.toOffset
if (skipRequest(offset, end))
Source.empty[Transaction]
else
client.transactionClient
.getTransactions(
offset,
terminates.toOffset,
filter,
ledgerId,
verbose = true,
token = bearer(jwt),
)
(jwt, ledgerId, filter, offset, terminates) => { implicit lc =>
{
val end = terminates.toOffset
if (skipRequest(offset, end))
Source.empty[Transaction]
else {
LedgerClientRequestTimeLogger.log(GetTransactionsLog) {
client.transactionClient
.getTransactions(
offset,
terminates.toOffset,
filter,
ledgerId,
verbose = true,
token = bearer(jwt),
)
}
}
}
}
private def skipRequest(start: LedgerOffset, end: Option[LedgerOffset]): Boolean = {
@ -197,52 +256,90 @@ object LedgerClientJwt {
}
}
def listKnownParties(client: DamlLedgerClient)(implicit ec: EC): ListKnownParties =
def listKnownParties(client: DamlLedgerClient)(implicit
ec: EC
): ListKnownParties =
jwt =>
client.partyManagementClient.listKnownParties(bearer(jwt)).requireHandling {
case Code.PERMISSION_DENIED => PermissionDenied
implicit lc => {
LedgerClientRequestTimeLogger
.logFuture(ListKnownPartiesLog) {
client.partyManagementClient.listKnownParties(bearer(jwt))
}
.requireHandling { case Code.PERMISSION_DENIED =>
PermissionDenied
}
}
def getParties(client: DamlLedgerClient)(implicit ec: EC): GetParties =
def getParties(client: DamlLedgerClient)(implicit
ec: EC
): GetParties =
(jwt, partyIds) =>
client.partyManagementClient.getParties(partyIds, bearer(jwt)).requireHandling {
case Code.PERMISSION_DENIED => PermissionDenied
implicit lc => {
LedgerClientRequestTimeLogger
.logFuture(GetPartiesLog) {
client.partyManagementClient.getParties(partyIds, bearer(jwt))
}
.requireHandling { case Code.PERMISSION_DENIED =>
PermissionDenied
}
}
def allocateParty(client: DamlLedgerClient): AllocateParty =
def allocateParty(client: DamlLedgerClient)(implicit
ec: EC
): AllocateParty =
(jwt, identifierHint, displayName) =>
client.partyManagementClient.allocateParty(
hint = identifierHint,
displayName = displayName,
token = bearer(jwt),
)
implicit lc => {
LedgerClientRequestTimeLogger.logFuture(AllocatePartyLog) {
client.partyManagementClient.allocateParty(
hint = identifierHint,
displayName = displayName,
token = bearer(jwt),
)
}
}
def listPackages(client: DamlLedgerClient): ListPackages =
def listPackages(client: DamlLedgerClient)(implicit
ec: EC
): ListPackages =
(jwt, ledgerId) =>
implicit lc => {
logger.trace("sending list packages request to ledger")
client.packageClient.listPackages(ledgerId, bearer(jwt))
LedgerClientRequestTimeLogger.logFuture(ListPackagesLog) {
client.packageClient.listPackages(ledgerId, bearer(jwt))
}
}
def getPackage(client: DamlLedgerClient): GetPackage =
def getPackage(client: DamlLedgerClient)(implicit
ec: EC
): GetPackage =
(jwt, ledgerId, packageId) =>
implicit lc => {
logger.trace("sending get packages request to ledger")
client.packageClient.getPackage(packageId, ledgerId, token = bearer(jwt))
LedgerClientRequestTimeLogger.logFuture(GetPackageLog) {
client.packageClient.getPackage(packageId, ledgerId, token = bearer(jwt))
}
}
def uploadDar(client: DamlLedgerClient): UploadDarFile =
def uploadDar(client: DamlLedgerClient)(implicit
ec: EC
): UploadDarFile =
(jwt, _, byteString) =>
implicit lc => {
logger.trace("sending upload dar request to ledger")
client.packageManagementClient.uploadDarFile(darFile = byteString, token = bearer(jwt))
LedgerClientRequestTimeLogger.logFuture(UploadDarFileLog) {
client.packageManagementClient.uploadDarFile(darFile = byteString, token = bearer(jwt))
}
}
def getMeteringReport(client: DamlLedgerClient): GetMeteringReport =
def getMeteringReport(client: DamlLedgerClient)(implicit
ec: EC
): GetMeteringReport =
(jwt, request) =>
implicit lc => {
logger.trace("sending metering report request to ledger")
client.meteringReportClient.getMeteringReport(request, bearer(jwt))
LedgerClientRequestTimeLogger.logFuture(GetMeteringReportLog) {
client.meteringReportClient.getMeteringReport(request, bearer(jwt))
}
}
// a shim error model to stand in for https://github.com/digital-asset/daml/issues/9834
@ -298,4 +395,57 @@ object LedgerClientJwt {
}
}
}
object LedgerClientRequestTimeLogger {
sealed abstract class RequestLog(klass: Class[_], val requestName: String)
extends Product
with Serializable {
final def className: String = klass.getSimpleName
}
case object SubmitAndWaitForTransactionLog
extends RequestLog(classOf[SynchronousCommandClient], "submitAndWaitForTransaction")
case object SubmitAndWaitForTransactionTreeLog
extends RequestLog(classOf[SynchronousCommandClient], "submitAndWaitForTransactionTree")
case object GetLedgerEndLog extends RequestLog(classOf[TransactionClient], "getLedgerEnd")
case object ListKnownPartiesLog
extends RequestLog(classOf[PartyManagementClient], "listKnownParties")
case object GetPartiesLog extends RequestLog(classOf[PartyManagementClient], "getParties")
case object AllocatePartyLog extends RequestLog(classOf[PartyManagementClient], "allocateParty")
case object ListPackagesLog extends RequestLog(classOf[PackageClient], "listPackages")
case object GetPackageLog extends RequestLog(classOf[PackageClient], "getPackages")
case object UploadDarFileLog
extends RequestLog(classOf[PackageManagementClient], "uploadDarFile")
case object GetMeteringReportLog
extends RequestLog(classOf[MeteringReportClient], "getMeteringReport")
case object GetActiveContractsLog
extends RequestLog(classOf[ActiveContractSetClient], "getActiveContracts")
case object GetTransactionsLog extends RequestLog(classOf[TransactionClient], "getTransactions")
private[LedgerClientJwt] def logMessage(startTime: Long, requestLog: RequestLog): String = {
s"Ledger client request ${requestLog.className} ${requestLog.requestName} executed, elapsed time: " +
s"${(System.nanoTime() - startTime) / 1000000L} ms"
}
private[http] def logFuture[T, C](
requestLog: RequestLog
)(block: => Future[T])(implicit ec: EC, lc: LoggingContextOf[C]): Future[T] = if (
logger.debug.isEnabled
) {
val start = System.nanoTime()
val futureResult = block
futureResult.andThen { case _ =>
logger.debug(logMessage(start, requestLog))
}
} else block
private[http] def log[T, C](
requestLog: RequestLog
)(block: => T)(implicit lc: LoggingContextOf[C]): T = if (logger.debug.isEnabled) {
val start = System.nanoTime()
val result = block
logger.debug(logMessage(start, requestLog))
result
} else block
}
}

View File

@ -10,6 +10,8 @@ import com.daml.nonempty._
import com.daml.jwt.domain.Jwt
import com.daml.ledger.api
import LedgerClientJwt.Grpc
import com.daml.http.util.Logging.{InstanceUUID, RequestID}
import com.daml.logging.LoggingContextOf
import scalaz.std.option._
import scalaz.std.scalaFuture._
import scalaz.std.string._
@ -29,6 +31,8 @@ class PartiesService(
def allocate(
jwt: Jwt,
request: domain.AllocatePartyRequest,
)(implicit
lc: LoggingContextOf[InstanceUUID with RequestID]
): Future[Error \/ domain.PartyDetails] = {
val et: ET[domain.PartyDetails] = for {
idHint <- either(
@ -36,7 +40,7 @@ class PartiesService(
): ET[Option[Ref.Party]]
apiParty <- rightT(
allocateParty(jwt, idHint, request.displayName)
allocateParty(jwt, idHint, request.displayName)(lc)
): ET[api.domain.PartyDetails]
domainParty = domain.PartyDetails.fromLedgerApi(apiParty)
@ -46,18 +50,22 @@ class PartiesService(
et.run
}
def allParties(jwt: Jwt): Future[Error \/ List[domain.PartyDetails]] =
listAllParties(jwt).map(
def allParties(jwt: Jwt)(implicit
lc: LoggingContextOf[InstanceUUID with RequestID]
): Future[Error \/ List[domain.PartyDetails]] =
listAllParties(jwt)(lc).map(
_ bimap (handleGrpcError, (_ map domain.PartyDetails.fromLedgerApi))
)
def parties(
jwt: Jwt,
identifiers: domain.PartySet,
)(implicit
lc: LoggingContextOf[InstanceUUID with RequestID]
): Future[Error \/ (Set[domain.PartyDetails], Set[domain.Party])] = {
val et: ET[(Set[domain.PartyDetails], Set[domain.Party])] = for {
apiPartyIds <- either(toLedgerApiPartySet(identifiers)): ET[OneAnd[Set, Ref.Party]]
apiPartyDetails <- eitherT(getParties(jwt, apiPartyIds))
apiPartyDetails <- eitherT(getParties(jwt, apiPartyIds)(lc))
.leftMap(handleGrpcError): ET[List[api.domain.PartyDetails]]
domainPartyDetails = apiPartyDetails.iterator
.map(domain.PartyDetails.fromLedgerApi)

View File

@ -102,27 +102,29 @@ object CommandServiceTest {
(
new CommandService(
submitAndWaitForTransaction = (_, req) =>
Future {
txns.add(req)
import lav1.event.{CreatedEvent, Event}, Event.Event.Created
val creation = Event(
Created(
CreatedEvent(
templateId = Some(
lav1.value
.Identifier(tplId.packageId, tplId.moduleName, tplId.entityName)
),
createArguments = Some(lav1.value.Record()),
_ =>
Future {
txns.add(req)
import lav1.event.{CreatedEvent, Event}, Event.Event.Created
val creation = Event(
Created(
CreatedEvent(
templateId = Some(
lav1.value
.Identifier(tplId.packageId, tplId.moduleName, tplId.entityName)
),
createArguments = Some(lav1.value.Record()),
)
)
)
)
\/-(SubmitAndWaitForTransactionResponse(Some(Transaction(events = Seq(creation)))))
},
\/-(SubmitAndWaitForTransactionResponse(Some(Transaction(events = Seq(creation)))))
},
submitAndWaitForTransactionTree = (_, req) =>
Future {
trees.add(req)
\/-(SubmitAndWaitForTransactionTreeResponse(Some(TransactionTree())))
},
_ =>
Future {
trees.add(req)
\/-(SubmitAndWaitForTransactionTreeResponse(Some(TransactionTree())))
},
),
txns.asScala,
trees.asScala,

View File

@ -40,7 +40,7 @@ class JwksVerifier(
connectionTimeoutUnit: TimeUnit = TimeUnit.SECONDS,
readTimeout: Long = 10,
readTimeoutUnit: TimeUnit = TimeUnit.SECONDS,
leewayOptions: Option[LeewayOptions] = None,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
) extends JwtVerifierBase {
private[this] val http =
@ -59,7 +59,7 @@ class JwksVerifier(
private[this] def getVerifier(keyId: String): Error \/ JwtVerifier = {
val jwk = http.get(keyId)
val publicKey = jwk.getPublicKey.asInstanceOf[RSAPublicKey]
RSA256Verifier(publicKey, leewayOptions)
RSA256Verifier(publicKey, jwtTimestampLeeway)
}
/** Looks up the verifier for the given keyId from the local cache.
@ -86,8 +86,8 @@ class JwksVerifier(
}
object JwksVerifier {
def apply(url: String, leewayOptions: Option[LeewayOptions] = None) =
new JwksVerifier(new URI(url).toURL, leewayOptions = leewayOptions)
def apply(url: String, jwtTimestampLeeway: Option[JwtTimestampLeeway] = None) =
new JwksVerifier(new URI(url).toURL, jwtTimestampLeeway = jwtTimestampLeeway)
final case class Error(what: Symbol, message: String)

View File

@ -7,8 +7,8 @@ import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.interfaces.{Verification}
final case class LeewayOptions(
leeway: Option[Long] = None,
final case class JwtTimestampLeeway(
default: Option[Long] = None,
expiresAt: Option[Long] = None,
issuedAt: Option[Long] = None,
notBefore: Option[Long] = None,
@ -17,14 +17,17 @@ final case class LeewayOptions(
trait Leeway {
def getVerifier(
algorithm: Algorithm,
mbLeewayOptions: Option[LeewayOptions] = None,
mbJwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): com.auth0.jwt.interfaces.JWTVerifier = {
def addLeeway(verification: Verification, leewayOptions: LeewayOptions): Verification = {
def addLeeway(
verification: Verification,
jwtTimestampLeeway: JwtTimestampLeeway,
): Verification = {
val mbOptionsActions: List[(Option[Long], (Verification, Long) => Verification)] = List(
(leewayOptions.leeway, _.acceptLeeway(_)),
(leewayOptions.expiresAt, _.acceptExpiresAt(_)),
(leewayOptions.issuedAt, _.acceptIssuedAt(_)),
(leewayOptions.notBefore, _.acceptNotBefore(_)),
(jwtTimestampLeeway.default, _.acceptLeeway(_)),
(jwtTimestampLeeway.expiresAt, _.acceptExpiresAt(_)),
(jwtTimestampLeeway.issuedAt, _.acceptIssuedAt(_)),
(jwtTimestampLeeway.notBefore, _.acceptNotBefore(_)),
)
mbOptionsActions.foldLeft(verification) {
case (verifier, (None, _)) => verifier
@ -32,7 +35,7 @@ trait Leeway {
}
}
val defaultVerifier = JWT.require(algorithm)
val verification = mbLeewayOptions.fold(defaultVerifier)(addLeeway(defaultVerifier, _))
val verification = mbJwtTimestampLeeway.fold(defaultVerifier)(addLeeway(defaultVerifier, _))
verification.build()
}
}

View File

@ -44,14 +44,17 @@ object JwtVerifier {
// HMAC256 validator factory
object HMAC256Verifier extends StrictLogging with Leeway {
def apply(secret: String, leewayOptions: Option[LeewayOptions] = None): Error \/ JwtVerifier =
def apply(
secret: String,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): Error \/ JwtVerifier =
\/.attempt {
logger.warn(
"HMAC256 JWT Validator is NOT recommended for production environments, please use RSA256!!!"
)
val algorithm = Algorithm.HMAC256(secret)
val verifier = getVerifier(algorithm, leewayOptions)
val verifier = getVerifier(algorithm, jwtTimestampLeeway)
new JwtVerifier(verifier)
}(e => Error(Symbol("HMAC256"), e.getMessage))
}
@ -60,17 +63,17 @@ object HMAC256Verifier extends StrictLogging with Leeway {
object ECDSAVerifier extends StrictLogging with Leeway {
def apply(
algorithm: Algorithm,
leewayOptions: Option[LeewayOptions] = None,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): Error \/ JwtVerifier =
\/.attempt {
val verifier = getVerifier(algorithm, leewayOptions)
val verifier = getVerifier(algorithm, jwtTimestampLeeway)
new JwtVerifier(verifier)
}(e => Error(Symbol(algorithm.getName), e.getMessage))
def fromCrtFile(
path: String,
algorithmPublicKey: ECPublicKey => Algorithm,
leewayOptions: Option[LeewayOptions] = None,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): Error \/ JwtVerifier = {
for {
key <- \/.fromEither(
@ -79,7 +82,7 @@ object ECDSAVerifier extends StrictLogging with Leeway {
.toEither
)
.leftMap(e => Error(Symbol("fromCrtFile"), e.getMessage))
verifier <- ECDSAVerifier(algorithmPublicKey(key), leewayOptions)
verifier <- ECDSAVerifier(algorithmPublicKey(key), jwtTimestampLeeway)
} yield verifier
}
}
@ -88,12 +91,12 @@ object ECDSAVerifier extends StrictLogging with Leeway {
object RSA256Verifier extends StrictLogging with Leeway {
def apply(
publicKey: RSAPublicKey,
leewayOptions: Option[LeewayOptions] = None,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): Error \/ JwtVerifier =
\/.attempt {
val algorithm = Algorithm.RSA256(publicKey, null)
val verifier = getVerifier(algorithm, leewayOptions)
val verifier = getVerifier(algorithm, jwtTimestampLeeway)
new JwtVerifier(verifier)
}(e => Error(Symbol("RSA256"), e.getMessage))
@ -107,12 +110,12 @@ object RSA256Verifier extends StrictLogging with Leeway {
def apply(
keyProvider: RSAKeyProvider,
leewayOptions: Option[LeewayOptions],
jwtTimestampLeeway: Option[JwtTimestampLeeway],
): Error \/ JwtVerifier =
\/.attempt {
val algorithm = Algorithm.RSA256(keyProvider)
val verifier = getVerifier(algorithm, leewayOptions)
val verifier = getVerifier(algorithm, jwtTimestampLeeway)
new JwtVerifier(verifier)
}(e => Error(Symbol("RSA256"), e.getMessage))
@ -122,7 +125,7 @@ object RSA256Verifier extends StrictLogging with Leeway {
*/
def fromCrtFile(
path: String,
leewayOptions: Option[LeewayOptions] = None,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
): Error \/ JwtVerifier = {
for {
rsaKey <- \/.fromEither(
@ -131,7 +134,7 @@ object RSA256Verifier extends StrictLogging with Leeway {
.toEither
)
.leftMap(e => Error(Symbol("fromCrtFile"), e.getMessage))
verifier <- RSA256Verifier.apply(rsaKey, leewayOptions)
verifier <- RSA256Verifier.apply(rsaKey, jwtTimestampLeeway)
} yield verifier
}
}

View File

@ -18,9 +18,9 @@ import org.scalatest.wordspec.AnyWordSpec
import scalaz.{\/, Show}
import scalaz.syntax.show._
class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyChecks {
class JwtTimestampLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyChecks {
import JWTLeewaySpec._
import JwtTimestampLeewaySpec._
"Jwt" when {
forAll(verifires) { (verifierType, algorithm, jwtVerifier) =>
@ -44,7 +44,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withExpiresAt(oneSecondEarlierFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(5), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(5), None, None, None))
jwtVerifier(leeway1).verifier
.verify(token)
}
@ -56,7 +56,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withExpiresAt(oneSecondEarlierFrom(now))
.sign(algorithm)
val expiresAt1 = Some(LeewayOptions(None, Some(5), None, None))
val expiresAt1 = Some(JwtTimestampLeeway(None, Some(5), None, None))
jwtVerifier(expiresAt1).verifier
.verify(token)
}
@ -81,7 +81,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withExpiresAt(fiveSecondsEarlierFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(1), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(1), None, None, None))
assertThrows[TokenExpiredException] {
jwtVerifier(leeway1).verifier
.verify(token)
@ -95,7 +95,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withExpiresAt(fiveSecondsEarlierFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(1), Some(10), None, None))
val leeway = Some(JwtTimestampLeeway(Some(1), Some(10), None, None))
jwtVerifier(leeway).verifier
.verify(token)
}
@ -107,7 +107,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withExpiresAt(fiveSecondsEarlierFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(10), Some(1), None, None))
val leeway = Some(JwtTimestampLeeway(Some(10), Some(1), None, None))
assertThrows[TokenExpiredException] {
jwtVerifier(leeway).verifier
.verify(token)
@ -132,7 +132,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withIssuedAt(oneSecondLaterFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(5), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(5), None, None, None))
jwtVerifier(leeway1).verifier
.verify(token)
}
@ -144,7 +144,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withIssuedAt(oneSecondLaterFrom(now))
.sign(algorithm)
val issuedAt1 = Some(LeewayOptions(None, None, Some(5), None))
val issuedAt1 = Some(JwtTimestampLeeway(None, None, Some(5), None))
jwtVerifier(issuedAt1).verifier
.verify(token)
}
@ -169,7 +169,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withIssuedAt(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(1), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(1), None, None, None))
assertThrows[InvalidClaimException] {
jwtVerifier(leeway1).verifier
.verify(token)
@ -183,7 +183,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withIssuedAt(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(1), None, Some(10), None))
val leeway = Some(JwtTimestampLeeway(Some(1), None, Some(10), None))
jwtVerifier(leeway).verifier
.verify(token)
}
@ -195,7 +195,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withIssuedAt(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(10), None, Some(1), None))
val leeway = Some(JwtTimestampLeeway(Some(10), None, Some(1), None))
assertThrows[InvalidClaimException] {
jwtVerifier(leeway).verifier
.verify(token)
@ -220,7 +220,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withNotBefore(oneSecondLaterFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(5), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(5), None, None, None))
jwtVerifier(leeway1).verifier
.verify(token)
}
@ -232,7 +232,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withNotBefore(oneSecondLaterFrom(now))
.sign(algorithm)
val notBefore1 = Some(LeewayOptions(None, None, None, Some(5)))
val notBefore1 = Some(JwtTimestampLeeway(None, None, None, Some(5)))
jwtVerifier(notBefore1).verifier
.verify(token)
}
@ -257,7 +257,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withNotBefore(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway1 = Some(LeewayOptions(Some(1), None, None, None))
val leeway1 = Some(JwtTimestampLeeway(Some(1), None, None, None))
assertThrows[InvalidClaimException] {
jwtVerifier(leeway1).verifier
.verify(token)
@ -271,7 +271,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withNotBefore(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(1), None, None, Some(10)))
val leeway = Some(JwtTimestampLeeway(Some(1), None, None, Some(10)))
jwtVerifier(leeway).verifier
.verify(token)
}
@ -283,7 +283,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
.withNotBefore(fiveSecondsLaterFrom(now))
.sign(algorithm)
val leeway = Some(LeewayOptions(Some(10), None, None, Some(1)))
val leeway = Some(JwtTimestampLeeway(Some(10), None, None, Some(1)))
assertThrows[InvalidClaimException] {
jwtVerifier(leeway).verifier
.verify(token)
@ -294,7 +294,7 @@ class JWTLeewaySpec extends AnyWordSpec with Matchers with TableDrivenPropertyCh
}
}
object JWTLeewaySpec extends TableDrivenPropertyChecks {
object JwtTimestampLeewaySpec extends TableDrivenPropertyChecks {
// HMAC
val secret = "secret key"
@ -322,12 +322,18 @@ object JWTLeewaySpec extends TableDrivenPropertyChecks {
val privateKeyECDSA512 = keyPairECDSA512.getPrivate.asInstanceOf[ECPrivateKey]
val publicKeyECDSA512 = keyPairECDSA512.getPublic.asInstanceOf[ECPublicKey]
val hmac256Verifier_ = HMAC256Verifier(secret, _: Option[LeewayOptions]).assertRight
val rsa256Verifier_ = RSA256Verifier(publicKeyRSA, _: Option[LeewayOptions]).assertRight
val hmac256Verifier_ = HMAC256Verifier(secret, _: Option[JwtTimestampLeeway]).assertRight
val rsa256Verifier_ = RSA256Verifier(publicKeyRSA, _: Option[JwtTimestampLeeway]).assertRight
val ecdsa256Verifier_ =
ECDSAVerifier(Algorithm.ECDSA256(publicKeyECDSA256, null), _: Option[LeewayOptions]).assertRight
ECDSAVerifier(
Algorithm.ECDSA256(publicKeyECDSA256, null),
_: Option[JwtTimestampLeeway],
).assertRight
val ecdsa512Verifier_ =
ECDSAVerifier(Algorithm.ECDSA512(publicKeyECDSA512, null), _: Option[LeewayOptions]).assertRight
ECDSAVerifier(
Algorithm.ECDSA512(publicKeyECDSA512, null),
_: Option[JwtTimestampLeeway],
).assertRight
val verifires = Table(
("verifier name", "algorithm", "verifier"),

View File

@ -12,6 +12,18 @@ object Dars {
// The TestDar object is generated by Bazel.
val resources: List[String] = TestDar.paths
// `DoNotLoadAtStartupResources` are not uploaded during the startup as being uploaded
// later in the conformance test.
// TODO when Interface Subscriptions land stable version,
// this can be updated to import classes instead of Strings
// import com.daml.ledger.test.{Carbonv2TestDar, Carbonv1TestDar}
private val DoNotLoadAtStartupResources: Set[String] = Set(
"ledger/test-common/carbonv1-tests-1.dev.dar",
"ledger/test-common/carbonv2-tests-1.dev.dar",
)
val startupResources: List[String] = resources.filterNot(DoNotLoadAtStartupResources.contains)
def read(name: String): ByteString =
ByteString.readFrom(getClass.getClassLoader.getResourceAsStream(name))

View File

@ -158,7 +158,7 @@ final class LedgerTestCasesRunner(
features = session.features,
)
// upload the dars sequentially to avoid conflicts
_ <- FutureUtil.sequential(Dars.resources)(uploadDar(context, _))
_ <- FutureUtil.sequential(Dars.startupResources)(uploadDar(context, _))
} yield ()
}
.map(_ => ())

View File

@ -2,6 +2,11 @@
# SPDX-License-Identifier: Apache-2.0
def deps(lf_version):
carbon_tests = [
"//ledger/test-common:carbonv1-tests-1.dev.scala",
"//ledger/test-common:carbonv2-tests-1.dev.scala",
]
additional_tests = carbon_tests if (lf_version == "1.dev") else []
return [
"//daml-lf/data",
"//daml-lf/transaction",
@ -28,4 +33,4 @@ def deps(lf_version):
"@maven//:io_grpc_grpc_netty",
"@maven//:io_netty_netty_handler",
"@maven//:org_slf4j_slf4j_api",
]
] + additional_tests

View File

@ -13,7 +13,7 @@ import com.daml.ledger.api.testtool.infrastructure.Allocation.{
allocate,
}
import com.daml.ledger.api.testtool.infrastructure.Assertions._
import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite
import com.daml.ledger.api.testtool.infrastructure.{Dars, LedgerTestSuite}
import com.daml.ledger.api.testtool.infrastructure.TransactionHelpers._
import com.daml.ledger.api.v1.event.Event.Event
import com.daml.ledger.api.v1.event.{CreatedEvent, InterfaceView}
@ -21,6 +21,7 @@ import com.daml.ledger.api.v1.transaction.Transaction
import com.daml.ledger.api.v1.transaction_filter.TransactionFilter
import com.daml.ledger.api.v1.value.{Identifier, Record}
import com.daml.ledger.test.semantic.InterfaceViews._
import com.daml.ledger.test.{Carbonv1TestDar, Carbonv2TestDar, carbonv1, carbonv2}
import scalaz.Tag
class InterfaceSubscriptionsIT extends LedgerTestSuite {
@ -524,6 +525,65 @@ class InterfaceSubscriptionsIT extends LedgerTestSuite {
}
})
test(
"ISTransactionsSubscribeBeforeTemplateCreated",
"Subscribing on transaction stream by interface before template is created",
allocate(SingleParty),
)(implicit ec => { case Participants(Participant(ledger, party)) =>
import ledger._
for {
notYetKnownInterfaceFailure <- flatTransactions(
getTransactionsRequest(
transactionFilter(Seq(party), Seq.empty, Seq((carbonv1.CarbonV1.I.id, true)))
)
).mustFail("Subscribing to not-yet known interface")
_ <- ledger.uploadDarFile(Dars.read(Carbonv1TestDar.path))
transactionFuture = flatTransactions(
take = 1,
getTransactionsRequest(
transactionFilter(Seq(party), Seq.empty, Seq((carbonv1.CarbonV1.I.id, true)))
)
// endless stream here as we would like to keep it open until
// template is uploaded and contract with this template is created
.update(
_.optionalEnd := None
),
)
_ = assertEquals(transactionFuture.isCompleted, false)
_ <- ledger.uploadDarFile(Dars.read(Carbonv2TestDar.path))
_ = assertEquals(transactionFuture.isCompleted, false)
contract <- create(party, carbonv2.CarbonV2.T(party, 21))
transactions <- transactionFuture
} yield {
assertGrpcError(
notYetKnownInterfaceFailure,
LedgerApiErrors.RequestValidation.InvalidArgument,
Some(s"Interfaces do not exist"),
)
assertLength("transaction should be found", 1, transactions)
val createdEvent = createdEvents(transactions(0)).head
assertLength("Create event has a view", 1, createdEvent.interfaceViews)
assertEquals(
"Create event template ID",
createdEvent.templateId.get.toString,
Tag.unwrap(carbonv2.CarbonV2.T.id).toString,
)
assertEquals("Create event contract ID", createdEvent.contractId, contract.toString)
assertViewEquals(createdEvent.interfaceViews, Tag.unwrap(carbonv1.CarbonV1.I.id)) { value =>
assertLength("View has 1 field", 1, value.fields)
assertEquals("View.a", value.fields(0).getValue.getInt64, 21)
}
}
})
private def updateTransaction(
emptyView: Boolean = false,
emptyWitness: Boolean = false,

View File

@ -3,7 +3,7 @@
package com.daml.ledger.runner.common
import com.daml.jwt.LeewayOptions
import com.daml.jwt.JwtTimestampLeeway
import com.daml.ledger.api.tls.TlsVersion.TlsVersion
import com.daml.ledger.api.tls.{SecretsUrl, TlsConfiguration, TlsVersion}
import com.daml.lf.data.Ref
@ -232,8 +232,8 @@ class PureConfigReaderWriter(secure: Boolean = true) {
implicit val userManagementConfigConvert: ConfigConvert[UserManagementConfig] =
deriveConvert[UserManagementConfig]
implicit val leewayConfigOptionsConvert: ConfigConvert[LeewayOptions] =
deriveConvert[LeewayOptions]
implicit val jwtTimestampLeewayConfigConvert: ConfigConvert[JwtTimestampLeeway] =
deriveConvert[JwtTimestampLeeway]
implicit val authServiceConfigUnsafeJwtHmac256Reader
: ConfigReader[AuthServiceConfig.UnsafeJwtHmac256] =

View File

@ -3,7 +3,7 @@
package com.daml.ledger.runner.common
import com.daml.jwt.LeewayOptions
import com.daml.jwt.JwtTimestampLeeway
import com.daml.lf.engine.EngineConfig
import com.daml.lf.interpretation.Limits
import com.daml.lf.language.LanguageVersion
@ -183,14 +183,14 @@ object ArbitraryConfig {
maxUsersPageSize = maxUsersPageSize,
)
def leewayOptionsGen: Gen[LeewayOptions] = {
def jwtTimestampLeewayGen: Gen[JwtTimestampLeeway] = {
for {
leeway <- Gen.option(Gen.posNum[Long])
default <- Gen.option(Gen.posNum[Long])
expiresAt <- Gen.option(Gen.posNum[Long])
issuedAt <- Gen.option(Gen.posNum[Long])
notBefore <- Gen.option(Gen.posNum[Long])
} yield LeewayOptions(
leeway = leeway,
} yield JwtTimestampLeeway(
default = default,
expiresAt = expiresAt,
issuedAt = issuedAt,
notBefore = notBefore,
@ -199,28 +199,28 @@ object ArbitraryConfig {
val UnsafeJwtHmac256 = for {
secret <- Gen.alphaStr
mbLeewayOptions <- Gen.option(leewayOptionsGen)
} yield AuthServiceConfig.UnsafeJwtHmac256(secret, mbLeewayOptions)
mbJwtTimestampLeeway <- Gen.option(jwtTimestampLeewayGen)
} yield AuthServiceConfig.UnsafeJwtHmac256(secret, mbJwtTimestampLeeway)
val JwtRs256Crt = for {
certificate <- Gen.alphaStr
mbLeewayOptions <- Gen.option(leewayOptionsGen)
} yield AuthServiceConfig.JwtRs256(certificate, mbLeewayOptions)
mbJwtTimestampLeeway <- Gen.option(jwtTimestampLeewayGen)
} yield AuthServiceConfig.JwtRs256(certificate, mbJwtTimestampLeeway)
val JwtEs256Crt = for {
certificate <- Gen.alphaStr
mbLeewayOptions <- Gen.option(leewayOptionsGen)
} yield AuthServiceConfig.JwtEs256(certificate, mbLeewayOptions)
mbJwtTimestampLeeway <- Gen.option(jwtTimestampLeewayGen)
} yield AuthServiceConfig.JwtEs256(certificate, mbJwtTimestampLeeway)
val JwtEs512Crt = for {
certificate <- Gen.alphaStr
mbLeewayOptions <- Gen.option(leewayOptionsGen)
} yield AuthServiceConfig.JwtEs512(certificate, mbLeewayOptions)
mbJwtTimestampLeeway <- Gen.option(jwtTimestampLeewayGen)
} yield AuthServiceConfig.JwtEs512(certificate, mbJwtTimestampLeeway)
val JwtRs256Jwks = for {
url <- Gen.alphaStr
mbLeewayOptions <- Gen.option(leewayOptionsGen)
} yield AuthServiceConfig.JwtRs256Jwks(url, mbLeewayOptions)
mbJwtTimestampLeeway <- Gen.option(jwtTimestampLeewayGen)
} yield AuthServiceConfig.JwtRs256Jwks(url, mbJwtTimestampLeeway)
val authServiceConfig = Gen.oneOf(
Gen.const(AuthServiceConfig.Wildcard),

View File

@ -3,7 +3,7 @@
package com.daml.ledger.runner.common
import com.daml.jwt.LeewayOptions
import com.daml.jwt.JwtTimestampLeeway
import com.daml.lf.interpretation.Limits
import com.daml.lf.language.LanguageVersion
import com.daml.lf.transaction.ContractKeyUniquenessMode
@ -358,8 +358,8 @@ class PureConfigReaderWriterSpec
it should "be isomorphic and support redaction" in forAll(ArbitraryConfig.authServiceConfig) {
generatedValue =>
val redacted = generatedValue match {
case AuthServiceConfig.UnsafeJwtHmac256(_, leeway) =>
AuthServiceConfig.UnsafeJwtHmac256("<REDACTED>", leeway)
case AuthServiceConfig.UnsafeJwtHmac256(_, jwtTimestampLeeway) =>
AuthServiceConfig.UnsafeJwtHmac256("<REDACTED>", jwtTimestampLeeway)
case _ => generatedValue
}
val insecureWriter = new PureConfigReaderWriter(false)
@ -395,60 +395,60 @@ class PureConfigReaderWriterSpec
"""
|type = unsafe-jwt-hmac-256
|secret = mysecret3
|leeway-options {
| leeway = 1
|jwt-timestamp-leeway {
| default = 1
|}
|""".stripMargin,
AuthServiceConfig.UnsafeJwtHmac256(
"mysecret3",
Some(LeewayOptions(Some(1), None, None, None)),
Some(JwtTimestampLeeway(Some(1), None, None, None)),
),
)
compare(
"""
|type = unsafe-jwt-hmac-256
|secret = mysecret3
|leeway-options {
|jwt-timestamp-leeway {
| expires-at = 2
|}
|""".stripMargin,
AuthServiceConfig.UnsafeJwtHmac256(
"mysecret3",
Some(LeewayOptions(None, Some(2), None, None)),
Some(JwtTimestampLeeway(None, Some(2), None, None)),
),
)
compare(
"""
|type = unsafe-jwt-hmac-256
|secret = mysecret3
|leeway-options {
|jwt-timestamp-leeway {
| issued-at = 3
|}
|""".stripMargin,
AuthServiceConfig.UnsafeJwtHmac256(
"mysecret3",
Some(LeewayOptions(None, None, Some(3), None)),
Some(JwtTimestampLeeway(None, None, Some(3), None)),
),
)
compare(
"""
|type = unsafe-jwt-hmac-256
|secret = mysecret3
|leeway-options {
|jwt-timestamp-leeway {
| not-before = 4
|}
|""".stripMargin,
AuthServiceConfig.UnsafeJwtHmac256(
"mysecret3",
Some(LeewayOptions(None, None, None, Some(4))),
Some(JwtTimestampLeeway(None, None, None, Some(4))),
),
)
compare(
"""
|type = unsafe-jwt-hmac-256
|secret = mysecret3
|leeway-options {
| leeway = 1
|jwt-timestamp-leeway {
| default = 1
| expires-at = 2
| issued-at = 3
| not-before = 4
@ -456,7 +456,7 @@ class PureConfigReaderWriterSpec
|""".stripMargin,
AuthServiceConfig.UnsafeJwtHmac256(
"mysecret3",
Some(LeewayOptions(Some(1), Some(2), Some(3), Some(4))),
Some(JwtTimestampLeeway(Some(1), Some(2), Some(3), Some(4))),
),
)
compare(

View File

@ -4,7 +4,13 @@
package com.daml.platform.apiserver
import com.auth0.jwt.algorithms.Algorithm
import com.daml.jwt.{ECDSAVerifier, HMAC256Verifier, JwksVerifier, RSA256Verifier, LeewayOptions}
import com.daml.jwt.{
ECDSAVerifier,
HMAC256Verifier,
JwksVerifier,
RSA256Verifier,
JwtTimestampLeeway,
}
import com.daml.ledger.api.auth.{AuthService, AuthServiceJWT, AuthServiceWildcard}
sealed trait AuthServiceConfig {
@ -18,31 +24,37 @@ object AuthServiceConfig {
}
/** [UNSAFE] Enables JWT-based authorization with shared secret HMAC256 signing: USE THIS EXCLUSIVELY FOR TESTING */
final case class UnsafeJwtHmac256(secret: String, leewayOptions: Option[LeewayOptions] = None)
extends AuthServiceConfig {
final case class UnsafeJwtHmac256(
secret: String,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
) extends AuthServiceConfig {
// note that HMAC256Verifier only returns an error for a `null` secret and UnsafeJwtHmac256 therefore can't throw an
// exception when reading secret from a config value
private lazy val verifier =
HMAC256Verifier(secret, leewayOptions).valueOr(err =>
HMAC256Verifier(secret, jwtTimestampLeeway).valueOr(err =>
throw new IllegalArgumentException(s"Invalid hmac secret ($secret): $err")
)
override def create(): AuthService = AuthServiceJWT(verifier)
}
/** Enables JWT-based authorization, where the JWT is signed by RSA256 with the verifying public key loaded from the given X509 certificate file (.crt) */
final case class JwtRs256(certificate: String, leewayOptions: Option[LeewayOptions] = None)
extends AuthServiceConfig {
final case class JwtRs256(
certificate: String,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
) extends AuthServiceConfig {
private lazy val verifier = RSA256Verifier
.fromCrtFile(certificate, leewayOptions)
.fromCrtFile(certificate, jwtTimestampLeeway)
.valueOr(err => throw new IllegalArgumentException(s"Failed to create RSA256 verifier: $err"))
override def create(): AuthService = AuthServiceJWT(verifier)
}
/** "Enables JWT-based authorization, where the JWT is signed by ECDSA256 with the verifying public key loaded from the given X509 certificate file (.crt)" */
final case class JwtEs256(certificate: String, leewayOptions: Option[LeewayOptions] = None)
extends AuthServiceConfig {
final case class JwtEs256(
certificate: String,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
) extends AuthServiceConfig {
private lazy val verifier = ECDSAVerifier
.fromCrtFile(certificate, Algorithm.ECDSA256(_, null), leewayOptions)
.fromCrtFile(certificate, Algorithm.ECDSA256(_, null), jwtTimestampLeeway)
.valueOr(err =>
throw new IllegalArgumentException(s"Failed to create ECDSA256 verifier: $err")
)
@ -50,10 +62,12 @@ object AuthServiceConfig {
}
/** Enables JWT-based authorization, where the JWT is signed by ECDSA512 with the verifying public key loaded from the given X509 certificate file (.crt) */
final case class JwtEs512(certificate: String, leewayOptions: Option[LeewayOptions] = None)
extends AuthServiceConfig {
final case class JwtEs512(
certificate: String,
jwtTimestampLeeway: Option[JwtTimestampLeeway] = None,
) extends AuthServiceConfig {
private lazy val verifier = ECDSAVerifier
.fromCrtFile(certificate, Algorithm.ECDSA512(_, null), leewayOptions)
.fromCrtFile(certificate, Algorithm.ECDSA512(_, null), jwtTimestampLeeway)
.valueOr(err =>
throw new IllegalArgumentException(s"Failed to create ECDSA512 verifier: $err")
)
@ -61,9 +75,9 @@ object AuthServiceConfig {
}
/** Enables JWT-based authorization, where the JWT is signed by RSA256 with the verifying public key loaded from the given JWKS URL */
final case class JwtRs256Jwks(url: String, leewayOptions: Option[LeewayOptions] = None)
final case class JwtRs256Jwks(url: String, jwtTimestampLeeway: Option[JwtTimestampLeeway] = None)
extends AuthServiceConfig {
private lazy val verifier = JwksVerifier(url, leewayOptions)
private lazy val verifier = JwksVerifier(url, jwtTimestampLeeway)
override def create(): AuthService = AuthServiceJWT(verifier)
}

View File

@ -75,14 +75,16 @@ da_scala_test_suite(
da_scala_dar_resources_library(
add_maven_tag = True,
daml_dir_names = [
"simple_package_party",
"simple_package_optional",
"simple_package_list",
"simple_package_text_map",
"simple_package_variant",
"simple_package_tuple",
],
daml_dir_names = {
"1.dev": [
"simple_package_party",
"simple_package_optional",
"simple_package_list",
"simple_package_text_map",
"simple_package_variant",
"simple_package_tuple",
],
},
daml_root_dir = "src/test/lib/daml",
lf_versions = ["1.dev"],
maven_name_prefix = "participant-state-test",

View File

@ -327,9 +327,9 @@ ledger {
# JWKS URL for jwt-rs-256-jwks algorithm
# url = "https://localhost/jwks.json"
#leeway-options {
#jwt-timestamp-leeway {
# # Define the default window in seconds in which the Not Before, Issued At and Expires At Claims will still be valid.
# leeway = 500
# default = 500
#
# # Set a specific leeway window in seconds in which the Expires At ("exp") Claim will still be valid.
# expires-at = 5

View File

@ -69,10 +69,7 @@ alias(
"//visibility:public",
],
deps = [
"//daml-lf/archive:daml_lf_1.dev_archive_proto_java",
"//daml-lf/archive:daml_lf_archive_reader",
"//ledger-api/grpc-definitions:ledger_api_proto_scala",
"//ledger/test-common:dar-files-%s-lib" % target,
"//libs-scala/scala-utils",
"//libs-scala/timer-utils",
"@maven//:ch_qos_logback_logback_classic",
@ -86,8 +83,13 @@ alias(
for target in lf_version_configuration_versions
]
# Correspond to the directories under src/test/lib/daml
test_names = [
# Carbon tests helps to test upgrades when packages are dependent on each other
carbon_test_names = [
"carbonv1",
"carbonv2", #carbonv2 depends on carbon v1
]
general_test_names = [
"benchtool",
"model",
"semantic",
@ -95,10 +97,20 @@ test_names = [
"package_management",
]
# Correspond to the directories under src/test/lib/daml
test_names = {
"1.dev": general_test_names + carbon_test_names,
"1.8": general_test_names,
"1.14": general_test_names,
}
da_scala_dar_resources_library(
add_maven_tag = True,
daml_dir_names = test_names,
daml_root_dir = "src/main/daml",
data_dependencies = {
"carbonv2-tests-1.dev": ["//ledger/test-common:carbonv1-tests-1.dev.build"],
},
enable_scenarios = True,
exclusions = {
"1.8": [
@ -144,7 +156,7 @@ da_scala_dar_resources_library(
],
),
]
for test_name in test_names
for test_name in test_names.get(target, [])
]
for target in lf_version_configuration_versions
]

View File

@ -0,0 +1,11 @@
-- Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
module CarbonV1 where
data View = View with
a : Int
interface I where
viewtype View

View File

@ -0,0 +1,17 @@
-- Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
module CarbonV2 where
import CarbonV1
template T
with
p : Party
a : Int
where
signatory p
interface instance I for T where
view = View with
a

View File

@ -1,26 +0,0 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.platform.testing
import java.util.zip.ZipInputStream
import com.daml.daml_lf_dev.DamlLf
import com.daml.ledger.test.TestDar
import com.daml.lf.archive.{Dar, DarParser}
import scala.util.Try
object TestDarReader {
def readCommonTestDar(testDar: TestDar): Try[Dar[DamlLf.Archive]] = read(testDar.path)
def read(path: String): Try[Dar[DamlLf.Archive]] = {
DarParser
.readArchive(
path,
new ZipInputStream(this.getClass.getClassLoader.getResourceAsStream(path)),
)
.toTry
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.platform.testing
import java.util.concurrent.atomic.AtomicInteger
import com.daml.ledger.api.v1.command_completion_service.CompletionStreamResponse
import io.grpc.Context
import io.grpc.stub.StreamObserver
import scala.concurrent.{Future, Promise}
object WaitForCompletionsObserver {
def apply(n: Int)(attach: StreamObserver[CompletionStreamResponse] => Unit): Future[Unit] = {
if (n < 1) {
Future.failed(
new IllegalArgumentException(
s"Invalid argument $n, `WaitForCompletionsObserver` requires a strictly positive integer as an argument"
)
)
} else {
val observer = new WaitForCompletionsObserver(n)
attach(observer)
observer.result
}
}
}
final class WaitForCompletionsObserver private (expectedCompletions: Int)
extends StreamObserver[CompletionStreamResponse] {
private val promise = Promise[Unit]()
private val counter = new AtomicInteger(0)
val result: Future[Unit] = promise.future
override def onNext(v: CompletionStreamResponse): Unit = {
val total = counter.addAndGet(v.completions.size)
if (total >= expectedCompletions) {
promise.trySuccess(())
Context.current().withCancellation().cancel(null)
()
}
}
override def onError(throwable: Throwable): Unit = {
val _ = promise.tryFailure(throwable)
}
override def onCompleted(): Unit = {
val _ = promise.tryFailure(new RuntimeException("no more completions"))
}
}

View File

@ -16,12 +16,13 @@ def da_scala_dar_resources_library(
maven_name_prefix = "",
exclusions = {},
enable_scenarios = False,
data_dependencies = {},
**kwargs):
"""
Define a Scala library with dar files as resources.
"""
for lf_version in lf_versions:
for daml_dir_name in daml_dir_names:
for daml_dir_name in daml_dir_names.get(lf_version, []):
# 1. Compile daml files
daml_compile_name = "%s-tests-%s" % (daml_dir_name, lf_version)
daml_compile_kwargs = {
@ -31,7 +32,11 @@ def da_scala_dar_resources_library(
"enable_scenarios": enable_scenarios,
}
daml_compile_kwargs.update(kwargs)
daml_compile(name = daml_compile_name, **daml_compile_kwargs)
daml_compile(
name = daml_compile_name,
data_dependencies = data_dependencies.get(daml_compile_name, []),
**daml_compile_kwargs
)
# 2. Generate lookup objects
genrule_name = "test-dar-lookup-%s" % lf_version
@ -49,11 +54,11 @@ object TestDar {{
EOF
""".format(lf_version = mangle_for_java(lf_version)) + "\n".join(["""
echo " \\"%s/%s-tests-%s.dar\\"," >> $@
""" % (native.package_name(), test_name, lf_version) for test_name in daml_dir_names]) + """
""" % (native.package_name(), test_name, lf_version) for test_name in daml_dir_names.get(lf_version, [])]) + """
echo " )\n}\n" >> $@
""" + "\n".join(["""
echo "case object %sTestDar extends TestDar { val path = \\"%s/%s-tests-%s.dar\\" }" >> $@
""" % (to_camel_case(test_name), native.package_name(), test_name, lf_version) for test_name in daml_dir_names])
""" % (to_camel_case(test_name), native.package_name(), test_name, lf_version) for test_name in daml_dir_names.get(lf_version, [])])
genrule_kwargs = {
"outs": ["TestDar-%s.scala" % mangle_for_java(lf_version)],
@ -65,7 +70,7 @@ echo "case object %sTestDar extends TestDar { val path = \\"%s/%s-tests-%s.dar\\
# 3. Build a Scala library with the above
filegroup_name = "dar-files-%s" % lf_version
filegroup_kwargs = {
"srcs": ["%s-tests-%s.dar" % (dar_name, lf_version) for dar_name in daml_dir_names],
"srcs": ["%s-tests-%s.dar" % (dar_name, lf_version) for dar_name in daml_dir_names.get(lf_version, [])],
}
filegroup_kwargs.update(kwargs)
native.filegroup(name = filegroup_name, **filegroup_kwargs)

View File

@ -8,7 +8,7 @@ import org.slf4j.{Logger, Marker}
private[logging] object LeveledLogger {
final class Trace(logger: Logger) extends LeveledLogger {
override protected def isEnabled: Boolean =
override def isEnabled: Boolean =
logger.isTraceEnabled()
override protected def log(msg: String): Unit =
logger.trace(msg)
@ -23,7 +23,7 @@ private[logging] object LeveledLogger {
}
final class Debug(logger: Logger) extends LeveledLogger {
override protected def isEnabled: Boolean =
override def isEnabled: Boolean =
logger.isDebugEnabled()
override protected def log(msg: String): Unit =
logger.debug(msg)
@ -38,7 +38,7 @@ private[logging] object LeveledLogger {
}
final class Info(logger: Logger) extends LeveledLogger {
override protected def isEnabled: Boolean =
override def isEnabled: Boolean =
logger.isInfoEnabled()
override protected def log(msg: String): Unit =
logger.info(msg)
@ -53,7 +53,7 @@ private[logging] object LeveledLogger {
}
final class Warn(logger: Logger) extends LeveledLogger {
override protected def isEnabled: Boolean =
override def isEnabled: Boolean =
logger.isWarnEnabled()
override protected def log(msg: String): Unit =
logger.warn(msg)
@ -68,7 +68,7 @@ private[logging] object LeveledLogger {
}
final class Error(logger: Logger) extends LeveledLogger {
override protected def isEnabled: Boolean =
override def isEnabled: Boolean =
logger.isErrorEnabled()
override protected def log(msg: String): Unit =
logger.error(msg)
@ -86,7 +86,7 @@ private[logging] object LeveledLogger {
private[logging] sealed abstract class LeveledLogger {
protected def isEnabled: Boolean
def isEnabled: Boolean
protected def log(msg: String): Unit
protected def log(msg: String, t: Throwable): Unit

View File

@ -193,6 +193,10 @@
type: jar-scala
- target: //ledger/test-common:test-common-1.dev
type: jar-scala
- target: //ledger/test-common:carbonv1-tests-1.dev.scala
type: jar-scala
- target: //ledger/test-common:carbonv2-tests-1.dev.scala
type: jar-scala
- target: //ledger-service/lf-value-json:lf-value-json
type: jar-scala
- target: //ledger-service/cli-opts:cli-opts

View File

@ -4,6 +4,7 @@
load("@build_environment//:configuration.bzl", "ghc_version", "sdk_version")
load("//bazel_tools/sh:sh.bzl", "sh_inline_test")
load("//daml-lf/language:daml-lf.bzl", "COMPILER_LF_VERSIONS", "versions")
load("@bazel_skylib//lib:paths.bzl", "paths")
_damlc = attr.label(
default = Label("//compiler/damlc:damlc-compile-only"),
@ -22,6 +23,7 @@ _zipper = attr.label(
def _daml_configure_impl(ctx):
project_name = ctx.attr.project_name
project_version = ctx.attr.project_version
data_dependencies = ctx.attr.data_dependencies
daml_yaml = ctx.outputs.daml_yaml
target = ctx.attr.target
opts = ["--target={}".format(target)] if target else []
@ -32,6 +34,7 @@ def _daml_configure_impl(ctx):
name: {name}
version: {version}
source: .
data-dependencies: [{data_dependencies} ]
dependencies: []
build-options: [{opts} ]
""".format(
@ -39,6 +42,7 @@ def _daml_configure_impl(ctx):
name = project_name,
version = project_version,
opts = ", ".join(opts),
data_dependencies = ", ".join(data_dependencies),
),
)
@ -60,6 +64,9 @@ _daml_configure = rule(
"target": attr.string(
doc = "Daml-LF version to output.",
),
"data_dependencies": attr.string_list(
doc = "Data dependencies.",
),
},
)
@ -265,6 +272,9 @@ def damlc_for_target(target):
else:
return "@damlc_legacy//:damlc_legacy"
def path_to_dar(data):
return Label(data).name + ".dar"
def daml_compile(
name,
srcs,
@ -273,12 +283,14 @@ def daml_compile(
project_name = None,
ghc_options = default_damlc_opts,
enable_scenarios = False,
data_dependencies = [],
**kwargs):
"Build a Daml project, with a generated daml.yaml."
if len(srcs) == 0:
fail("daml_compile: Expected `srcs' to be non-empty.")
daml_yaml = name + ".yaml"
_daml_configure(
data_dependencies = [path_to_dar(data) for data in data_dependencies],
name = name + ".configure",
project_name = project_name or name,
project_version = version,
@ -290,7 +302,7 @@ def daml_compile(
name = name + ".build",
daml_yaml = daml_yaml,
srcs = srcs,
dar_dict = {},
dar_dict = {data: path_to_dar(data) for data in data_dependencies},
dar = name + ".dar",
ghc_options =
ghc_options +