From 4c2e0da8ac3a14804036a87d4a97d0d8a736b8bb Mon Sep 17 00:00:00 2001 From: mait Date: Mon, 30 Jun 2025 19:38:09 +0300 Subject: [PATCH 1/8] UnitTypeExtractor interface introduced to avoid passing around possibly outdated shard confs. --- go.mod | 52 +------ go.sum | 211 +-------------------------- testutils/tokens/id.go | 5 +- txsystem/money/unit_data_types.go | 4 +- txsystem/orchestration/unit_types.go | 4 +- txsystem/tokens/unit_types.go | 4 +- types/identifiers.go | 7 +- types/partition_description.go | 40 ++++- types/root_trust_base.go | 30 +++- types/root_trust_base_test.go | 4 +- types/tx_proof.go | 3 +- types/tx_record.go | 2 +- types/unicity_certificate.go | 17 ++- types/unicity_certificate_test.go | 12 +- types/unit_proof.go | 6 +- types/unit_proof_test.go | 26 ++-- 16 files changed, 120 insertions(+), 307 deletions(-) diff --git a/go.mod b/go.mod index b61c293..06795f1 100644 --- a/go.mod +++ b/go.mod @@ -9,65 +9,15 @@ require ( ) require ( - github.com/DataDog/zstd v1.5.6 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/VictoriaMetrics/fastcache v1.12.2 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.15.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cockroachdb/errors v1.11.3 // indirect - github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v1.1.2 // indirect - github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/consensys/bavard v0.1.22 // indirect - github.com/consensys/gnark-crypto v0.14.0 // indirect - github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/ethereum/c-kzg-4844 v1.0.3 // indirect - github.com/ethereum/go-verkle v0.2.2 // indirect - github.com/getsentry/sentry-go v0.29.1 // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/gofrs/flock v0.12.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.1 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.60.1 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/supranational/blst v0.3.13 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tklauser/go-sysconf v0.3.14 // indirect - github.com/tklauser/numcpus v0.9.0 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 3ad8fd6..f2c50f3 100644 --- a/go.sum +++ b/go.sum @@ -1,245 +1,40 @@ -github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY= -github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.15.0 h1:DiCRMscZsGyYePE9AR3sVhKqUXCt5IZvkX5AfAc5xLQ= -github.com/bits-and-blooms/bitset v1.15.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= -github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= -github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 h1:pU88SPhIFid6/k0egdR5V6eALQYq2qbSmukrkgIh/0A= -github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= -github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= -github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= -github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= -github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E= -github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0= -github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= -github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= -github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= -github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= -github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= -github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= -github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/getsentry/sentry-go v0.29.1 h1:DyZuChN8Hz3ARxGVV8ePaNXh1dQ7d76AiB117xcREwA= -github.com/getsentry/sentry-go v0.29.1/go.mod h1:x3AtIzN01d6SiWkderzaH28Tm0lgkafpJ5Bm3li39O0= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= -github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= -github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= -github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= -github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= -github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= -github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= -github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo= -github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/testutils/tokens/id.go b/testutils/tokens/id.go index b903f36..a050066 100644 --- a/testutils/tokens/id.go +++ b/testutils/tokens/id.go @@ -25,8 +25,9 @@ generator functions in this package. Prefer to create test specific PDR and use it's ComposeUnitID method! */ -func PDR() types.PartitionDescriptionRecord { - return testPDR +func PDR() *types.PartitionDescriptionRecord { + copy := testPDR + return © } /* diff --git a/txsystem/money/unit_data_types.go b/txsystem/money/unit_data_types.go index ebdf566..a976977 100644 --- a/txsystem/money/unit_data_types.go +++ b/txsystem/money/unit_data_types.go @@ -20,8 +20,8 @@ type BillData struct { Counter uint64 `json:"counter,string"` // The transaction counter of this bill } -func NewUnitData(unitID types.UnitID, pdr *types.PartitionDescriptionRecord) (types.UnitData, error) { - typeID, err := pdr.ExtractUnitType(unitID) +func NewUnitData(unitID types.UnitID, unitTypeExtractor types.UnitTypeExtractor) (types.UnitData, error) { + typeID, err := unitTypeExtractor(unitID) if err != nil { return nil, fmt.Errorf("extracting unit type: %w", err) } diff --git a/txsystem/orchestration/unit_types.go b/txsystem/orchestration/unit_types.go index 70ccd9b..f032d50 100644 --- a/txsystem/orchestration/unit_types.go +++ b/txsystem/orchestration/unit_types.go @@ -10,8 +10,8 @@ const ( VarUnitType = 1 ) -func NewUnitData(unitID types.UnitID, pdr *types.PartitionDescriptionRecord) (types.UnitData, error) { - typeID, err := pdr.ExtractUnitType(unitID) +func NewUnitData(unitID types.UnitID, unitTypeExtractor types.UnitTypeExtractor) (types.UnitData, error) { + typeID, err := unitTypeExtractor(unitID) if err != nil { return nil, fmt.Errorf("extracting type ID: %w", err) } diff --git a/txsystem/tokens/unit_types.go b/txsystem/tokens/unit_types.go index 3e54008..443ae45 100644 --- a/txsystem/tokens/unit_types.go +++ b/txsystem/tokens/unit_types.go @@ -51,8 +51,8 @@ func GenerateUnitID(txo *types.TransactionOrder, shardConf *types.PartitionDescr return nil } -func NewUnitData(unitID types.UnitID, pdr *types.PartitionDescriptionRecord) (types.UnitData, error) { - typeID, err := pdr.ExtractUnitType(unitID) +func NewUnitData(unitID types.UnitID, unitTypeExtractor types.UnitTypeExtractor) (types.UnitData, error) { + typeID, err := unitTypeExtractor(unitID) if err != nil { return nil, fmt.Errorf("extracting type ID: %w", err) } diff --git a/types/identifiers.go b/types/identifiers.go index cca1bba..dc4c3ef 100644 --- a/types/identifiers.go +++ b/types/identifiers.go @@ -31,6 +31,9 @@ type ( // UnitID is the extended identifier, combining the type and the unit identifiers. UnitID []byte + + // UnitTypeExtractor is a function that extracts unit type from UnitID + UnitTypeExtractor func(UnitID) (uint32, error) ) func (uid UnitID) Compare(key UnitID) int { @@ -45,8 +48,8 @@ func (uid UnitID) Eq(id UnitID) bool { return bytes.Equal(uid, id) } -func (uid UnitID) TypeMustBe(typeID uint32, pdr *PartitionDescriptionRecord) error { - tid, err := pdr.ExtractUnitType(uid) +func (uid UnitID) TypeMustBe(typeID uint32, unitTypeExtractor UnitTypeExtractor) error { + tid, err := unitTypeExtractor(uid) if err != nil { return fmt.Errorf("extracting unit type from unit ID: %w", err) } diff --git a/types/partition_description.go b/types/partition_description.go index 1be07c8..2f2ca17 100644 --- a/types/partition_description.go +++ b/types/partition_description.go @@ -115,6 +115,9 @@ func (pdr *PartitionDescriptionRecord) Verify(prev *PartitionDescriptionRecord) if pdr.NetworkID != prev.NetworkID { return fmt.Errorf("invalid network id, provided %d previous %d", pdr.NetworkID, prev.NetworkID) } + if pdr.PartitionTypeID != prev.PartitionTypeID { + return fmt.Errorf("invalid partition type id, provided %d previous %d", pdr.PartitionTypeID, prev.PartitionTypeID) + } if pdr.PartitionID != prev.PartitionID { return fmt.Errorf("invalid partition id, provided %d previous %d", pdr.PartitionID, prev.PartitionID) } @@ -137,14 +140,33 @@ func (pdr *PartitionDescriptionRecord) Hash(hashAlgorithm crypto.Hash) ([]byte, return hasher.Sum() } +func (pdr *PartitionDescriptionRecord) GetVersion() ABVersion { + if pdr == nil || pdr.Version == 0 { + return 1 + } + return pdr.Version +} + func (pdr *PartitionDescriptionRecord) GetNetworkID() NetworkID { return pdr.NetworkID } +func (pdr *PartitionDescriptionRecord) GetPartitionTypeID() PartitionTypeID { + return pdr.PartitionTypeID +} + func (pdr *PartitionDescriptionRecord) GetPartitionID() PartitionID { return pdr.PartitionID } +func (pdr *PartitionDescriptionRecord) GetShardID() ShardID { + return pdr.ShardID +} + +func (pdr *PartitionDescriptionRecord) GetPartitionParams() map[string]string { + return pdr.PartitionParams +} + /* UnitIDValidator returns function which checks that unit ID passed as argument has correct length and that the unit belongs into the given shard. @@ -207,20 +229,13 @@ func (pdr *PartitionDescriptionRecord) ExtractUnitType(id UnitID) (uint32, error return 0, fmt.Errorf("expected unit ID length %d bytes, got %d bytes", idLen, len(id)) } - // we relay on the fact that valid PDR has "pdr.UnitIDLen >= 64" ie it's safe to read four bytes + // we rely on the fact that valid PDR has "pdr.UnitIDLen >= 64" ie it's safe to read four bytes idx := len(id) - 1 v := uint32(id[idx]) | (uint32(id[idx-1]) << 8) | (uint32(id[idx-2]) << 16) | (uint32(id[idx-3]) << 24) mask := uint32(0xFFFFFFFF) >> (32 - pdr.TypeIDLen) return v & mask, nil } -func (pdr *PartitionDescriptionRecord) GetVersion() ABVersion { - if pdr == nil || pdr.Version == 0 { - return 1 - } - return pdr.Version -} - func (pdr *PartitionDescriptionRecord) MarshalCBOR() ([]byte, error) { type alias PartitionDescriptionRecord if pdr.Version == 0 { @@ -236,3 +251,12 @@ func (pdr *PartitionDescriptionRecord) UnmarshalCBOR(data []byte) error { } return EnsureVersion(pdr, pdr.Version, 1) } + +func (pdr *PartitionDescriptionRecord) FindValidator(nodeID string) *NodeInfo { + for _, validator := range pdr.Validators { + if validator.NodeID == nodeID { + return validator + } + } + return nil +} diff --git a/types/root_trust_base.go b/types/root_trust_base.go index 78bbb0b..c9c01ae 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -16,6 +16,8 @@ import ( type ( RootTrustBase interface { GetNetworkID() NetworkID + GetEpoch() uint64 + GetEpochStart() uint64 VerifyQuorumSignatures(data []byte, signatures map[string]hex.Bytes) error VerifySignature(data []byte, sig []byte, nodeID string) (uint64, error) GetQuorumThreshold() uint64 @@ -28,7 +30,7 @@ type ( Version ABVersion `json:"version"` NetworkID NetworkID `json:"networkId"` Epoch uint64 `json:"epoch"` // current epoch number - EpochStartRound uint64 `json:"epochStartRound"` // root chain round number when the epoch begins + EpochStart uint64 `json:"epochStartRound"` // root chain round number when the epoch begins RootNodes []*NodeInfo `json:"rootNodes"` // list of all root nodes for the current epoch QuorumThreshold uint64 `json:"quorumThreshold"` // amount of alpha required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash @@ -51,6 +53,8 @@ type ( Option func(c *trustBaseConf) trustBaseConf struct { + epoch uint64 + epochStart uint64 quorumThreshold uint64 } ) @@ -93,8 +97,8 @@ func NewTrustBaseGenesis(networkID NetworkID, rootNodes []*NodeInfo, opts ...Opt return &RootTrustBaseV1{ Version: 1, NetworkID: networkID, - Epoch: 1, - EpochStartRound: 1, + Epoch: c.epoch, + EpochStart: c.epochStart, RootNodes: rootNodes, QuorumThreshold: c.quorumThreshold, StateHash: nil, @@ -111,6 +115,18 @@ func WithQuorumThreshold(threshold uint64) Option { } } +func WithEpoch(epoch uint64) Option { + return func(c *trustBaseConf) { + c.epoch = epoch + } +} + +func WithEpochStart(epochStart uint64) Option { + return func(c *trustBaseConf) { + c.epochStart = epochStart + } +} + // IsValid validates that all fields are correctly set and public keys are correct. func (n *NodeInfo) IsValid() error { if n == nil { @@ -239,6 +255,14 @@ func (r *RootTrustBaseV1) GetNetworkID() NetworkID { return r.NetworkID } +func (r *RootTrustBaseV1) GetEpoch() uint64 { + return r.Epoch +} + +func (r *RootTrustBaseV1) GetEpochStart() uint64 { + return r.EpochStart +} + func (r *RootTrustBaseV1) MarshalCBOR() ([]byte, error) { type alias RootTrustBaseV1 if r.Version == 0 { diff --git a/types/root_trust_base_test.go b/types/root_trust_base_test.go index f472fa4..864685d 100644 --- a/types/root_trust_base_test.go +++ b/types/root_trust_base_test.go @@ -72,8 +72,8 @@ func TestNewTrustBaseGenesis(t *testing.T) { }, verifyFunc: func(t *testing.T, tb *RootTrustBaseV1) { // verify values - require.EqualValues(t, 1, tb.Epoch) - require.EqualValues(t, 1, tb.EpochStartRound) + require.EqualValues(t, 0, tb.Epoch) + require.EqualValues(t, 0, tb.EpochStart) require.Len(t, tb.RootNodes, 3) require.EqualValues(t, 3, tb.QuorumThreshold) require.EqualValues(t, hex.Bytes(nil), tb.StateHash) diff --git a/types/tx_proof.go b/types/tx_proof.go index b501b16..c2fb6fd 100644 --- a/types/tx_proof.go +++ b/types/tx_proof.go @@ -107,7 +107,8 @@ func VerifyTxInclusion(txRecordProof *TxRecordProof, tb RootTrustBase, hashAlgor return fmt.Errorf("failed to get transaction order: %w", err) } - if err := uc.Verify(tb, hashAlgorithm, txo.PartitionID, nil); err != nil { + // TODO: actual shardID extracted + if err := uc.Verify(tb, hashAlgorithm, txo.PartitionID, ShardID{}, nil); err != nil { return fmt.Errorf("invalid unicity certificate: %w", err) } // h ← plain_tree_output(C, H(P)) diff --git a/types/tx_record.go b/types/tx_record.go index 52a157c..16aed58 100644 --- a/types/tx_record.go +++ b/types/tx_record.go @@ -207,7 +207,7 @@ func (t *TxRecordProof) Verify(getTrustBase func(epoch uint64) (RootTrustBase, e return errors.New("invalid UC: missing UnicitySeal") } trustBase, err := getTrustBase(uc.UnicitySeal.Epoch) - if err != nil { + if err != nil || trustBase == nil { return fmt.Errorf("acquiring trust base: %w", err) } return VerifyTxProof(t, trustBase, crypto.SHA256) diff --git a/types/unicity_certificate.go b/types/unicity_certificate.go index ff81626..44ed611 100644 --- a/types/unicity_certificate.go +++ b/types/unicity_certificate.go @@ -51,7 +51,8 @@ func (x *UnicityCertificate) IsValid(partitionID PartitionID, shardConfHash []by return nil } -func (x *UnicityCertificate) Verify(tb RootTrustBase, algorithm crypto.Hash, partitionID PartitionID, shardConfHash []byte) error { +// TODO: verify shardID also +func (x *UnicityCertificate) Verify(tb RootTrustBase, algorithm crypto.Hash, partitionID PartitionID, shardID ShardID, shardConfHash []byte) error { if err := x.IsValid(partitionID, shardConfHash); err != nil { return fmt.Errorf("invalid unicity certificate: %w", err) } @@ -145,6 +146,20 @@ func (x *UnicityCertificate) GetShardID() ShardID { return x.ShardTreeCertificate.Shard } +func (x *UnicityCertificate) GetShardEpoch() uint64 { + if x != nil && x.InputRecord != nil { + return x.InputRecord.Epoch + } + return 0 +} + +func (x *UnicityCertificate) GetRootEpoch() uint64 { + if x != nil && x.UnicitySeal != nil { + return x.UnicitySeal.Epoch + } + return 0 +} + // CheckNonEquivocatingCertificates checks if provided certificates are equivocating // NB! order is important, also it is assumed that validity of both UCs is checked before // The algorithm is based on Yellowpaper: "Algorithm 6 Checking two UC-s for equivocation" diff --git a/types/unicity_certificate_test.go b/types/unicity_certificate_test.go index 8c146db..ce577b6 100644 --- a/types/unicity_certificate_test.go +++ b/types/unicity_certificate_test.go @@ -75,7 +75,7 @@ func TestUnicityCertificate_IsValid(t *testing.T) { require.EqualValues(t, 0, uc.GetRoundNumber()) require.EqualValues(t, 0, uc.GetRootRoundNumber()) require.Nil(t, uc.GetStateHash()) - require.ErrorIs(t, uc.Verify(nil, crypto.SHA256, 0, nil), ErrUnicityCertificateIsNil) + require.ErrorIs(t, uc.Verify(nil, crypto.SHA256, 0, ShardID{}, nil), ErrUnicityCertificateIsNil) }) t.Run("invalid input record", func(t *testing.T) { @@ -209,25 +209,25 @@ func TestUnicityCertificate_Verify(t *testing.T) { } } - require.NoError(t, validUC(t, sid0, &ir0, trHash0, shardConf0Hash).Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf0Hash)) - require.NoError(t, validUC(t, sid1, &ir1, trHash1, shardConf1Hash).Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf1Hash)) + require.NoError(t, validUC(t, sid0, &ir0, trHash0, shardConf0Hash).Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf0.ShardID, shardConf0Hash)) + require.NoError(t, validUC(t, sid1, &ir1, trHash1, shardConf1Hash).Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf0.ShardID, shardConf1Hash)) t.Run("IsValid", func(t *testing.T) { // check that IsValid is called uc := UnicityCertificate{Version: 1} - require.EqualError(t, uc.Verify(nil, crypto.SHA256, 0, nil), + require.EqualError(t, uc.Verify(nil, crypto.SHA256, 0, ShardID{}, nil), "invalid unicity certificate: invalid input record: input record is nil") }) t.Run("tb is nil", func(t *testing.T) { uc := validUC(t, sid0, &ir0, trHash0, shardConf0Hash) - require.EqualError(t, uc.Verify(nil, crypto.SHA256, shardConf0.PartitionID, shardConf0Hash), "verifying unicity seal: root node info is missing") + require.EqualError(t, uc.Verify(nil, crypto.SHA256, shardConf0.PartitionID, shardConf0.ShardID, shardConf0Hash), "verifying unicity seal: root node info is missing") }) t.Run("invalid root hash", func(t *testing.T) { uc := validUC(t, sid0, &ir0, trHash0, shardConf0Hash) uc.UnicitySeal.Hash = []byte{1, 2, 3} - require.EqualError(t, uc.Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf0Hash), + require.EqualError(t, uc.Verify(tb, crypto.SHA256, shardConf0.PartitionID, shardConf0.ShardID, shardConf0Hash), "unicity seal hash 010203 does not match with the root hash of the unicity tree F06B596575FAE5F211C9738A657C55A13D06F7E22CE40F02A4682FDA7C1FD44F") }) } diff --git a/types/unit_proof.go b/types/unit_proof.go index 7c6089a..4508efe 100644 --- a/types/unit_proof.go +++ b/types/unit_proof.go @@ -62,7 +62,7 @@ type ( } UnicityCertificateValidator interface { - Validate(uc *UnicityCertificate, shardConfHash []byte) error + Validate(uc *UnicityCertificate, shardConf *PartitionDescriptionRecord, trustBase RootTrustBase) error } ) @@ -93,7 +93,7 @@ func (u *UnitStateProof) getUCv1() (*UnicityCertificate, error) { return uc, nil } -func (u *UnitStateProof) Verify(algorithm crypto.Hash, unitState *UnitState, ucv UnicityCertificateValidator, shardConfHash []byte) error { +func (u *UnitStateProof) Verify(algorithm crypto.Hash, unitState *UnitState, ucv UnicityCertificateValidator, shardConf *PartitionDescriptionRecord, trustBase RootTrustBase) error { if err := u.IsValid(); err != nil { return fmt.Errorf("invalid unit state proof: %w", err) } @@ -105,7 +105,7 @@ func (u *UnitStateProof) Verify(algorithm crypto.Hash, unitState *UnitState, ucv if err != nil { return fmt.Errorf("failed to get unicity certificate: %w", err) } - if err := ucv.Validate(uc, shardConfHash); err != nil { + if err := ucv.Validate(uc, shardConf, trustBase); err != nil { return fmt.Errorf("invalid unicity certificate: %w", err) } diff --git a/types/unit_proof_test.go b/types/unit_proof_test.go index 50005c8..9535405 100644 --- a/types/unit_proof_test.go +++ b/types/unit_proof_test.go @@ -12,11 +12,11 @@ import ( type alwaysValid struct{} type alwaysInvalid struct{} -func (a *alwaysValid) Validate(*UnicityCertificate, []byte) error { +func (a *alwaysValid) Validate(uc *UnicityCertificate, shardConf *PartitionDescriptionRecord, trustBase RootTrustBase) error { return nil } -func (a alwaysInvalid) Validate(*UnicityCertificate, []byte) error { +func (a *alwaysInvalid) Validate(uc *UnicityCertificate, shardConf *PartitionDescriptionRecord, trustBase RootTrustBase) error { return errors.New("invalid uc") } @@ -27,13 +27,13 @@ func TestVerifyUnitStateProof(t *testing.T) { t.Run("unit state proof is nil", func(t *testing.T) { data := &UnitState{} var usp *UnitStateProof - require.EqualError(t, usp.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid unit state proof: unit state proof is nil") + require.EqualError(t, usp.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid unit state proof: unit state proof is nil") }) t.Run("unit ID missing", func(t *testing.T) { data := &UnitState{} usp := &UnitStateProof{} - require.EqualError(t, usp.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid unit state proof: unit ID is unassigned") + require.EqualError(t, usp.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid unit state proof: unit ID is unassigned") }) t.Run("unit tree cert missing", func(t *testing.T) { @@ -41,7 +41,7 @@ func TestVerifyUnitStateProof(t *testing.T) { UnitID: []byte{0}, } data := &UnitState{} - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid unit state proof: unit tree cert is nil") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid unit state proof: unit tree cert is nil") }) t.Run("state tree cert missing", func(t *testing.T) { @@ -50,7 +50,7 @@ func TestVerifyUnitStateProof(t *testing.T) { UnitTreeCert: &UnitTreeCert{}, } data := &UnitState{} - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid unit state proof: state tree cert is nil") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid unit state proof: state tree cert is nil") }) t.Run("unicity certificate missing", func(t *testing.T) { @@ -60,7 +60,7 @@ func TestVerifyUnitStateProof(t *testing.T) { StateTreeCert: &StateTreeCert{}, } data := &UnitState{} - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid unit state proof: unicity certificate is nil") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid unit state proof: unicity certificate is nil") }) t.Run("invalid unicity certificate", func(t *testing.T) { @@ -71,7 +71,7 @@ func TestVerifyUnitStateProof(t *testing.T) { UnicityCertificate: emptyUC, } data := &UnitState{} - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysInvalid{}, nil), "invalid unicity certificate: invalid uc") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysInvalid{}, nil, nil), "invalid unicity certificate: invalid uc") }) t.Run("missing unit data", func(t *testing.T) { @@ -81,7 +81,7 @@ func TestVerifyUnitStateProof(t *testing.T) { StateTreeCert: &StateTreeCert{}, UnicityCertificate: emptyUC, } - require.EqualError(t, proof.Verify(crypto.SHA256, nil, &alwaysValid{}, nil), "unit state is nil") + require.EqualError(t, proof.Verify(crypto.SHA256, nil, &alwaysValid{}, nil, nil), "unit state is nil") }) t.Run("unit data hash invalid", func(t *testing.T) { @@ -92,7 +92,7 @@ func TestVerifyUnitStateProof(t *testing.T) { UnicityCertificate: emptyUC, } data := &UnitState{} - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "unit state hash does not match unit state hash in unit tree cert") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "unit state hash does not match unit state hash in unit tree cert") }) t.Run("invalid summary value", func(t *testing.T) { @@ -109,7 +109,7 @@ func TestVerifyUnitStateProof(t *testing.T) { uc.InputRecord = &InputRecord{SummaryValue: []byte{1}} proof.UnicityCertificate, err = uc.MarshalCBOR() require.NoError(t, err) - require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid summary value: expected 01, got 0000000000000000") + require.EqualError(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid summary value: expected 01, got 0000000000000000") }) t.Run("invalid state root hash", func(t *testing.T) { @@ -126,7 +126,7 @@ func TestVerifyUnitStateProof(t *testing.T) { uc.InputRecord = &InputRecord{SummaryValue: []byte{0, 0, 0, 0, 0, 0, 0, 0}} proof.UnicityCertificate, err = uc.MarshalCBOR() require.NoError(t, err) - require.ErrorContains(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil), "invalid state root hash") + require.ErrorContains(t, proof.Verify(crypto.SHA256, data, &alwaysValid{}, nil, nil), "invalid state root hash") }) t.Run("verify - ok", func(t *testing.T) { @@ -146,7 +146,7 @@ func TestVerifyUnitStateProof(t *testing.T) { uc.InputRecord.Hash = hash proof.UnicityCertificate, err = uc.MarshalCBOR() require.NoError(t, err) - require.NoError(t, proof.Verify(crypto.SHA256, unitState, &alwaysValid{}, nil), "unexpected error") + require.NoError(t, proof.Verify(crypto.SHA256, unitState, &alwaysValid{}, nil, nil), "unexpected error") }) } From d9501cd49500a60722effcfbad0717df5fb26184 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Thu, 30 Oct 2025 14:51:48 +0200 Subject: [PATCH 2/8] add GetVersion method to RootTrustBase interface --- types/root_trust_base.go | 1 + 1 file changed, 1 insertion(+) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index 8924337..a6c1ebc 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -15,6 +15,7 @@ import ( type ( RootTrustBase interface { + GetVersion() Version GetNetworkID() NetworkID GetEpoch() uint64 GetEpochStart() uint64 From e8062dba868341782a3bc4f75f801db5743f2982 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Mon, 3 Nov 2025 16:52:26 +0200 Subject: [PATCH 3/8] add trust base verification method --- types/root_trust_base.go | 58 +++++++++++-- types/root_trust_base_test.go | 136 ++++++++++++++++++++++++++++-- types/tx_proof_test.go | 21 ++--- types/unicity_certificate_test.go | 2 +- types/unicity_seal_test.go | 4 +- 5 files changed, 194 insertions(+), 27 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index a6c1ebc..ca03949 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "cmp" "crypto" "errors" @@ -37,7 +38,7 @@ type ( StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash ChangeRecordHash hex.Bytes `json:"changeRecordHash"` // epoch change request hash PreviousEntryHash hex.Bytes `json:"previousEntryHash"` // previous trust base entry hash - Signatures map[string]hex.Bytes `json:"signatures"` // signatures of previous epoch validators, over all fields except for the signatures fields itself + Signatures map[string]hex.Bytes `json:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself } NodeInfo struct { @@ -54,14 +55,15 @@ type ( Option func(c *trustBaseConf) trustBaseConf struct { - epoch uint64 - epochStart uint64 - quorumThreshold uint64 + epoch uint64 + epochStart uint64 + quorumThreshold uint64 + previousTrustBaseHash hex.Bytes } ) -// NewTrustBaseGenesis creates new unsigned root trust base with default parameters. -func NewTrustBaseGenesis(networkID NetworkID, rootNodes []*NodeInfo, opts ...Option) (*RootTrustBaseV1, error) { +// NewTrustBase creates new unsigned root trust base. +func NewTrustBase(networkID NetworkID, rootNodes []*NodeInfo, opts ...Option) (*RootTrustBaseV1, error) { if len(rootNodes) == 0 { return nil, errors.New("nodes list is empty") } @@ -104,7 +106,7 @@ func NewTrustBaseGenesis(networkID NetworkID, rootNodes []*NodeInfo, opts ...Opt QuorumThreshold: c.quorumThreshold, StateHash: nil, ChangeRecordHash: nil, - PreviousEntryHash: nil, + PreviousEntryHash: c.previousTrustBaseHash, Signatures: make(map[string]hex.Bytes), }, nil } @@ -128,6 +130,12 @@ func WithEpochStart(epochStart uint64) Option { } } +func WithPreviousTrustBaseHash(previousTrustBaseHash hex.Bytes) Option { + return func(c *trustBaseConf) { + c.previousTrustBaseHash = previousTrustBaseHash + } +} + // IsValid validates that all fields are correctly set and public keys are correct. func (n *NodeInfo) IsValid() error { if n == nil { @@ -289,3 +297,39 @@ func (r *RootTrustBaseV1) getRootNode(nodeID string) *NodeInfo { } return nil } + +// Verify verifies the trust base +// +// Genesis trust base: +// - Epoch must be zero. +// +// Non-genesis trust base must extend previous trust base: +// - The network identifiers must match. +// - The epoch number must be strictly greater than the previous epoch number. +// - The epoch start round must be strictly greater than the previous epoch start round. +// - The hash of the previous trust must match the previousEntryHash. +func (r *RootTrustBaseV1) Verify(prev *RootTrustBaseV1) error { + if prev == nil { + if r.Epoch != 0 { + return fmt.Errorf("genesis trust base epoch must be 0, got %d", r.Epoch) + } + return nil + } + if r.NetworkID != prev.NetworkID { + return fmt.Errorf("invalid network id, got %d previous %d", r.NetworkID, prev.NetworkID) + } + if r.Epoch != prev.Epoch+1 { + return fmt.Errorf("invalid epoch, got %d previous %d", r.Epoch, prev.Epoch) + } + if r.EpochStart <= prev.EpochStart { + return fmt.Errorf("invalid epoch start, got %d previous %d", r.EpochStart, prev.EpochStart) + } + prevHash, err := prev.Hash(crypto.SHA256) + if err != nil { + return fmt.Errorf("failed to calculate previous trust base hash: %w", err) + } + if !bytes.Equal(r.PreviousEntryHash, prevHash) { + return errors.New("previous trust base hash does not match") + } + return nil +} diff --git a/types/root_trust_base_test.go b/types/root_trust_base_test.go index 7f14acc..18b28cc 100644 --- a/types/root_trust_base_test.go +++ b/types/root_trust_base_test.go @@ -1,13 +1,15 @@ package types import ( + "crypto" "fmt" "strconv" "testing" + "github.com/stretchr/testify/require" + abcrypto "github.com/unicitynetwork/bft-go-base/crypto" "github.com/unicitynetwork/bft-go-base/types/hex" - "github.com/stretchr/testify/require" ) func TestNodeInfo_IsValid(t *testing.T) { @@ -186,7 +188,7 @@ func TestNewTrustBaseGenesis(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tb, err := NewTrustBaseGenesis(NetworkMainNet, tt.args.nodes, tt.args.opts...) + tb, err := NewTrustBase(NetworkMainNet, tt.args.nodes, tt.args.opts...) if tt.wantErrStr != "" { require.ErrorContains(t, err, tt.wantErrStr) require.Nil(t, tb) @@ -203,7 +205,7 @@ func TestNewTrustBaseGenesis(t *testing.T) { func TestSignAndVerify(t *testing.T) { keys := genKeys(1) - tb, err := NewTrustBaseGenesis( + tb, err := NewTrustBase( NetworkMainNet, []*NodeInfo{&NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}}, ) @@ -222,7 +224,7 @@ func TestSignAndVerify(t *testing.T) { func Test_RootTrustBaseV1_CBOR(t *testing.T) { keys := genKeys(3) - tb, err := NewTrustBaseGenesis( + tb, err := NewTrustBase( NetworkMainNet, []*NodeInfo{ &NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}, @@ -287,14 +289,14 @@ func genKeys(count int) map[string]key { return keys } -func NewTrustBase(t *testing.T, verifiers ...abcrypto.Verifier) RootTrustBase { +func NewTrustBaseT(t *testing.T, verifiers ...abcrypto.Verifier) RootTrustBase { var nodes []*NodeInfo for _, v := range verifiers { sigKey, err := v.MarshalPublicKey() require.NoError(t, err) nodes = append(nodes, &NodeInfo{NodeID: "test", SigKey: sigKey, Stake: 1}) } - tb, err := NewTrustBaseGenesis(NetworkMainNet, nodes) + tb, err := NewTrustBase(NetworkMainNet, nodes) require.NoError(t, err) return tb } @@ -306,7 +308,127 @@ func NewTrustBaseFromVerifiers(t *testing.T, verifiers map[string]abcrypto.Verif require.NoError(t, err) nodes = append(nodes, &NodeInfo{NodeID: nodeID, SigKey: sigKey, Stake: 1}) } - tb, err := NewTrustBaseGenesis(NetworkMainNet, nodes) + tb, err := NewTrustBase(NetworkMainNet, nodes) require.NoError(t, err) return tb } + +func TestRootTrustBaseV1_Verify(t *testing.T) { + keys := genKeys(1) + node := &NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1} + + // create trust base for epoch 0 + tb0, err := NewTrustBase(NetworkLocal, []*NodeInfo{node}, WithEpoch(0), WithEpochStart(5)) + require.NoError(t, err) + + // calculate trust base hash + tb0Hash, err := tb0.Hash(crypto.SHA256) + require.NoError(t, err) + + // create trust base for epoch 1 + tb1, err := NewTrustBase(NetworkLocal, []*NodeInfo{node}, + WithEpoch(1), + WithEpochStart(10), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + tests := []struct { + name string + prev *RootTrustBaseV1 + curr *RootTrustBaseV1 + wantErr string + }{ + { + name: "genesis trust base with epoch zero ok", + prev: nil, + curr: tb0, + }, + { + name: "genesis trust base with non-zero epoch nok", + prev: nil, + curr: func() *RootTrustBaseV1 { + g := *tb0 + g.Epoch = 1 + return &g + }(), + wantErr: "genesis trust base epoch must be 0, got 1", + }, + { + name: "extend ok", + prev: tb0, + curr: tb1, + }, + { + name: "extend with different network id nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.NetworkID = b.NetworkID + 1 + return &b + }(), + wantErr: "invalid network id, got 4 previous 3", + }, + { + name: "extend with same epoch nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.Epoch = 0 + return &b + }(), + wantErr: "invalid epoch, got 0 previous 0", + }, + { + name: "extend with epoch not incremented by 1 nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.Epoch = 2 + return &b + }(), + wantErr: "invalid epoch, got 2 previous 0", + }, + { + name: "extend with same epoch start nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.EpochStart = 5 + return &b + }(), + wantErr: "invalid epoch start, got 5 previous 5", + }, + { + name: "extend with smaller epoch start nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.EpochStart = 4 + return &b + }(), + wantErr: "invalid epoch start, got 4 previous 5", + }, + { + name: "extend with invalid previous hash nok", + prev: tb0, + curr: func() *RootTrustBaseV1 { + b := *tb1 + b.PreviousEntryHash = []byte{1, 2, 3} + return &b + }(), + wantErr: "previous trust base hash does not match", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.curr.Verify(tt.prev) + if tt.wantErr != "" { + require.ErrorContains(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/types/tx_proof_test.go b/types/tx_proof_test.go index 5ed5edc..6857068 100644 --- a/types/tx_proof_test.go +++ b/types/tx_proof_test.go @@ -5,9 +5,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + abcrypto "github.com/unicitynetwork/bft-go-base/crypto" testsig "github.com/unicitynetwork/bft-go-base/testutils/sig" - "github.com/stretchr/testify/require" ) func TestNewTxProof(t *testing.T) { @@ -45,21 +46,21 @@ func TestVerifyInc(t *testing.T) { block := createBlock(t, "test", signer, createTx(t)) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) require.NoError(t, VerifyTxInclusion(proof, tb, crypto.SHA256)) }) t.Run("Test tx record proof is nil", func(t *testing.T) { _, verifier := testsig.CreateSignerAndVerifier(t) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) require.EqualError(t, VerifyTxInclusion(nil, tb, crypto.SHA256), "transaction record proof is nil") }) t.Run("Test tx record is nil", func(t *testing.T) { _, verifier := testsig.CreateSignerAndVerifier(t) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) proof := &TxRecordProof{TxProof: &TxProof{Version: 1}} require.EqualError(t, VerifyTxInclusion(proof, tb, crypto.SHA256), "transaction record is nil") @@ -67,7 +68,7 @@ func TestVerifyInc(t *testing.T) { t.Run("Test tx order is nil", func(t *testing.T) { _, verifier := testsig.CreateSignerAndVerifier(t) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) txr := &TransactionRecord{Version: 1, ServerMetadata: &ServerMetadata{SuccessIndicator: TxStatusSuccessful}} proof := &TxRecordProof{TxRecord: txr, TxProof: &TxProof{Version: 1}} @@ -79,7 +80,7 @@ func TestVerifyInc(t *testing.T) { block := createBlock(t, "test", signer, createTx(t)) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) uc, err := proof.TxProof.GetUC() require.NoError(t, err) uc.UnicityTreeCertificate.Partition = 1 @@ -94,7 +95,7 @@ func TestVerifyInc(t *testing.T) { block := createBlock(t, "test", signer, createTx(t)) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) proof.TxProof.BlockHeaderHash = make([]byte, 32) require.EqualError(t, VerifyTxInclusion(proof, tb, crypto.SHA256), "proof block hash does not match to block hash in unicity certificate") @@ -107,7 +108,7 @@ func TestVerifyTxProof(t *testing.T) { block := createBlock(t, "test", signer, createTx(t)) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) require.NoError(t, VerifyTxInclusion(proof, tb, crypto.SHA256)) }) @@ -119,7 +120,7 @@ func TestVerifyTxProof(t *testing.T) { block := createBlock(t, "test", signer, txr) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) require.EqualError(t, VerifyTxProof(proof, tb, crypto.SHA256), "transaction failed") }) @@ -131,7 +132,7 @@ func TestVerifyTxProof(t *testing.T) { block := createBlock(t, "test", signer, txr) proof, err := NewTxRecordProof(block, 0, crypto.SHA256) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) require.EqualError(t, VerifyTxProof(proof, tb, crypto.SHA256), "transaction failed") }) diff --git a/types/unicity_certificate_test.go b/types/unicity_certificate_test.go index 5bc11bf..2732a5b 100644 --- a/types/unicity_certificate_test.go +++ b/types/unicity_certificate_test.go @@ -149,7 +149,7 @@ func TestUnicityCertificate_Verify(t *testing.T) { trHash1 := bytes.Repeat([]byte{11}, 32) signer, verifier := testsig.CreateSignerAndVerifier(t) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) // must use const timestamp to have deterministic UC hash const curTimestamp uint64 = 1731504540 diff --git a/types/unicity_seal_test.go b/types/unicity_seal_test.go index abe65e4..1fb45d6 100644 --- a/types/unicity_seal_test.go +++ b/types/unicity_seal_test.go @@ -80,7 +80,7 @@ func TestUnicitySeal_IsValid(t *testing.T) { func TestUnicitySeal_Verify(t *testing.T) { signer, verifier := testsig.CreateSignerAndVerifier(t) - trustBase := NewTrustBase(t, verifier) + trustBase := NewTrustBaseT(t, verifier) randomHash := test.RandomBytes(32) // createUS returns UnicitySeal which is not signed but otherwise valid(ish) @@ -197,7 +197,7 @@ func TestUnicitySeal_cbor(t *testing.T) { err := seal.Sign("test", signer) require.NoError(t, err) - tb := NewTrustBase(t, verifier) + tb := NewTrustBaseT(t, verifier) err = seal.Verify(tb) require.NoError(t, err) From a097536b79b72306bd446229b6e7d06b2b7ac4d4 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Wed, 12 Nov 2025 22:33:36 +0200 Subject: [PATCH 4/8] add bson tags to root trust base --- types/root_trust_base.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index ca03949..8f5c837 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -29,16 +29,16 @@ type ( RootTrustBaseV1 struct { _ struct{} `cbor:",toarray"` - Version Version `json:"version"` - NetworkID NetworkID `json:"networkId"` - Epoch uint64 `json:"epoch"` // current epoch number - EpochStart uint64 `json:"epochStartRound"` // root chain round number when the epoch begins - RootNodes []*NodeInfo `json:"rootNodes"` // list of all root nodes for the current epoch - QuorumThreshold uint64 `json:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node - StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash - ChangeRecordHash hex.Bytes `json:"changeRecordHash"` // epoch change request hash - PreviousEntryHash hex.Bytes `json:"previousEntryHash"` // previous trust base entry hash - Signatures map[string]hex.Bytes `json:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself + Version Version `json:"version" bson:"version"` + NetworkID NetworkID `json:"networkId" bson:"networkId"` + Epoch uint64 `json:"epoch" bson:"epoch"` // current epoch number + EpochStart uint64 `json:"epochStartRound" bson:"epochStartRound"` // root chain round number when the epoch begins + RootNodes []*NodeInfo `json:"rootNodes" bson:"rootNodes"` // list of all root nodes for the current epoch + QuorumThreshold uint64 `json:"quorumThreshold" bson:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node + StateHash hex.Bytes `json:"stateHash" bson:"stateHash"` // unicity tree root hash + ChangeRecordHash hex.Bytes `json:"changeRecordHash" bson:"changeRecordHash"` // epoch change request hash + PreviousEntryHash hex.Bytes `json:"previousEntryHash" bson:"previousEntryHash"` // previous trust base entry hash + Signatures map[string]hex.Bytes `json:"signatures" bson:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself } NodeInfo struct { From 687b1725138893bb824f81623b33407ae7aade92 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Thu, 20 Nov 2025 16:43:28 +0200 Subject: [PATCH 5/8] add previous epoch signatures to root trust base --- types/root_trust_base.go | 98 +++++++++++-- types/root_trust_base_test.go | 261 ++++++++++++++++++++++++++++++---- 2 files changed, 315 insertions(+), 44 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index 8f5c837..dcad833 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -28,17 +28,18 @@ type ( } RootTrustBaseV1 struct { - _ struct{} `cbor:",toarray"` - Version Version `json:"version" bson:"version"` - NetworkID NetworkID `json:"networkId" bson:"networkId"` - Epoch uint64 `json:"epoch" bson:"epoch"` // current epoch number - EpochStart uint64 `json:"epochStartRound" bson:"epochStartRound"` // root chain round number when the epoch begins - RootNodes []*NodeInfo `json:"rootNodes" bson:"rootNodes"` // list of all root nodes for the current epoch - QuorumThreshold uint64 `json:"quorumThreshold" bson:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node - StateHash hex.Bytes `json:"stateHash" bson:"stateHash"` // unicity tree root hash - ChangeRecordHash hex.Bytes `json:"changeRecordHash" bson:"changeRecordHash"` // epoch change request hash - PreviousEntryHash hex.Bytes `json:"previousEntryHash" bson:"previousEntryHash"` // previous trust base entry hash - Signatures map[string]hex.Bytes `json:"signatures" bson:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself + _ struct{} `cbor:",toarray"` + Version Version `json:"version" bson:"version"` + NetworkID NetworkID `json:"networkId" bson:"networkId"` + Epoch uint64 `json:"epoch" bson:"epoch"` // current epoch number + EpochStart uint64 `json:"epochStartRound" bson:"epochStartRound"` // root chain round number when the epoch begins + RootNodes []*NodeInfo `json:"rootNodes" bson:"rootNodes"` // list of all root nodes for the current epoch + QuorumThreshold uint64 `json:"quorumThreshold" bson:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node + StateHash hex.Bytes `json:"stateHash" bson:"stateHash"` // unicity tree root hash + ChangeRecordHash hex.Bytes `json:"changeRecordHash" bson:"changeRecordHash"` // epoch change request hash + PreviousEntryHash hex.Bytes `json:"previousEntryHash" bson:"previousEntryHash"` // previous trust base entry hash + Signatures map[string]hex.Bytes `json:"signatures" bson:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself + PreviousEpochSignatures map[string]hex.Bytes `json:"previousEpochSignatures" bson:"previousEpochSignatures"` // signatures of previous epoch validators, over all fields except for this field itself } NodeInfo struct { @@ -189,6 +190,29 @@ func (r *RootTrustBaseV1) Sign(nodeID string, signer abcrypto.Signer) error { return nil } +// SignPrevious signs the trust base entry, storing the signature to PreviousEpochSignatures map. +func (r *RootTrustBaseV1) SignPrevious(nodeID string, signer abcrypto.Signer) error { + if nodeID == "" { + return errors.New("node identifier is empty") + } + if signer == nil { + return errors.New("signer is nil") + } + sb, err := r.PreviousEpochSigBytes() + if err != nil { + return err + } + sig, err := signer.SignBytes(sb) + if err != nil { + return fmt.Errorf("signing failed: %w", err) + } + if r.PreviousEpochSignatures == nil { + r.PreviousEpochSignatures = make(map[string]hex.Bytes) + } + r.PreviousEpochSignatures[nodeID] = sig + return nil +} + // Hash hashes the entire structure including the signatures. func (r *RootTrustBaseV1) Hash(hashAlgo crypto.Hash) ([]byte, error) { hasher := abhash.New(hashAlgo.New()) @@ -196,9 +220,20 @@ func (r *RootTrustBaseV1) Hash(hashAlgo crypto.Hash) ([]byte, error) { return hasher.Sum() } -// SigBytes serializes all fields expect for the signatures field. +// SigBytes serializes all fields expect for the Signatures and PreviousEpochSignatures fields. func (r RootTrustBaseV1) SigBytes() ([]byte, error) { r.Signatures = nil + r.PreviousEpochSignatures = nil + bs, err := r.MarshalCBOR() + if err != nil { + return nil, fmt.Errorf("failed to marshal root trust base: %w", err) + } + return bs, nil +} + +// PreviousEpochSigBytes serializes all fields expect for the PreviousEpochSignatures field. +func (r RootTrustBaseV1) PreviousEpochSigBytes() ([]byte, error) { + r.PreviousEpochSignatures = nil bs, err := r.MarshalCBOR() if err != nil { return nil, fmt.Errorf("failed to marshal root trust base: %w", err) @@ -298,7 +333,10 @@ func (r *RootTrustBaseV1) getRootNode(nodeID string) *NodeInfo { return nil } -// Verify verifies the trust base +// Verify verifies the trust base, including the signatures. +// +// Common for all trust bases: +// - The current epoch signatures must be valid and reach quorum. // // Genesis trust base: // - Epoch must be zero. @@ -308,7 +346,17 @@ func (r *RootTrustBaseV1) getRootNode(nodeID string) *NodeInfo { // - The epoch number must be strictly greater than the previous epoch number. // - The epoch start round must be strictly greater than the previous epoch start round. // - The hash of the previous trust must match the previousEntryHash. +// - The previous epoch signatures must be valid and reach quorum. func (r *RootTrustBaseV1) Verify(prev *RootTrustBaseV1) error { + if err := r.IsValid(prev); err != nil { + return err + } + return r.VerifySignatures(prev) +} + +// IsValid verifies the trust base without verifying the signatures. +// Use VerifySignatures to verify the signatures. +func (r *RootTrustBaseV1) IsValid(prev *RootTrustBaseV1) error { if prev == nil { if r.Epoch != 0 { return fmt.Errorf("genesis trust base epoch must be 0, got %d", r.Epoch) @@ -333,3 +381,27 @@ func (r *RootTrustBaseV1) Verify(prev *RootTrustBaseV1) error { } return nil } + +// VerifySignatures verifies the trust base is signed by quorum. +func (r *RootTrustBaseV1) VerifySignatures(prev *RootTrustBaseV1) error { + // verify current epoch signatures + sigBytes, err := r.SigBytes() + if err != nil { + return fmt.Errorf("failed to get sig bytes: %w", err) + } + if err := r.VerifyQuorumSignatures(sigBytes, r.Signatures); err != nil { + return fmt.Errorf("failed to verify signatures: %w", err) + } + + // verify previous epoch signatures + if prev != nil { + prevSigBytes, err := r.PreviousEpochSigBytes() + if err != nil { + return fmt.Errorf("failed to get previous epoch sig bytes: %w", err) + } + if err := prev.VerifyQuorumSignatures(prevSigBytes, r.PreviousEpochSignatures); err != nil { + return fmt.Errorf("failed to verify previous epoch signatures: %w", err) + } + } + return nil +} diff --git a/types/root_trust_base_test.go b/types/root_trust_base_test.go index 18b28cc..c775f2e 100644 --- a/types/root_trust_base_test.go +++ b/types/root_trust_base_test.go @@ -66,9 +66,9 @@ func TestNewTrustBaseGenesis(t *testing.T) { name: "default settings ok", args: args{ nodes: []*NodeInfo{ - &NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}, - &NodeInfo{NodeID: "2", SigKey: keys["2"].publicKey, Stake: 1}, - &NodeInfo{NodeID: "3", SigKey: keys["3"].publicKey, Stake: 1}, + {NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}, + {NodeID: "2", SigKey: keys["2"].publicKey, Stake: 1}, + {NodeID: "3", SigKey: keys["3"].publicKey, Stake: 1}, }, unicityTreeRootHash: []byte{1}, }, @@ -207,7 +207,7 @@ func TestSignAndVerify(t *testing.T) { keys := genKeys(1) tb, err := NewTrustBase( NetworkMainNet, - []*NodeInfo{&NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}}, + []*NodeInfo{{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}}, ) require.NoError(t, err) @@ -227,9 +227,9 @@ func Test_RootTrustBaseV1_CBOR(t *testing.T) { tb, err := NewTrustBase( NetworkMainNet, []*NodeInfo{ - &NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}, - &NodeInfo{NodeID: "2", SigKey: keys["2"].publicKey, Stake: 1}, - &NodeInfo{NodeID: "3", SigKey: keys["3"].publicKey, Stake: 1}, + {NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1}, + {NodeID: "2", SigKey: keys["2"].publicKey, Stake: 1}, + {NodeID: "3", SigKey: keys["3"].publicKey, Stake: 1}, }, ) require.NoError(t, err) @@ -314,24 +314,49 @@ func NewTrustBaseFromVerifiers(t *testing.T, verifiers map[string]abcrypto.Verif } func TestRootTrustBaseV1_Verify(t *testing.T) { - keys := genKeys(1) - node := &NodeInfo{NodeID: "1", SigKey: keys["1"].publicKey, Stake: 1} + keys := genKeys(4) + nodes := make([]*NodeInfo, 0, len(keys)) + for i := 1; i <= len(keys); i++ { + nodeID := strconv.Itoa(i) + nodes = append(nodes, &NodeInfo{NodeID: nodeID, SigKey: keys[nodeID].publicKey, Stake: 1}) + } // create trust base for epoch 0 - tb0, err := NewTrustBase(NetworkLocal, []*NodeInfo{node}, WithEpoch(0), WithEpochStart(5)) + tb0Signed, err := NewTrustBase(NetworkLocal, nodes, WithEpoch(0), WithEpochStart(5)) require.NoError(t, err) + require.EqualValues(t, 3, tb0Signed.QuorumThreshold) - // calculate trust base hash - tb0Hash, err := tb0.Hash(crypto.SHA256) + // sign trust base for epoch 0 + for i := 1; i <= 3; i++ { + err := tb0Signed.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + + // create unsigned trust base for epoch 0 + tb0Unsigned, err := NewTrustBase(NetworkLocal, nodes, WithEpoch(0), WithEpochStart(5)) require.NoError(t, err) - // create trust base for epoch 1 - tb1, err := NewTrustBase(NetworkLocal, []*NodeInfo{node}, + // calculate signed trust base hash + tb0Hash, err := tb0Signed.Hash(crypto.SHA256) + require.NoError(t, err) + + // create a valid trust base for epoch 1, signed by both previous and current validators + tb1Signed, err := NewTrustBase(NetworkLocal, nodes, WithEpoch(1), - WithEpochStart(10), + WithEpochStart(50), WithPreviousTrustBaseHash(tb0Hash), ) require.NoError(t, err) + require.EqualValues(t, 3, tb0Signed.QuorumThreshold) + + for i := 1; i <= 3; i++ { + err := tb1Signed.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + for i := 1; i <= 3; i++ { + err = tb1Signed.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } tests := []struct { name string @@ -342,13 +367,19 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { { name: "genesis trust base with epoch zero ok", prev: nil, - curr: tb0, + curr: tb0Signed, + }, + { + name: "genesis trust base without signatures nok", + prev: nil, + curr: tb0Unsigned, + wantErr: "failed to verify signatures: quorum not reached, signed_votes=0 quorum_threshold=3", }, { name: "genesis trust base with non-zero epoch nok", prev: nil, curr: func() *RootTrustBaseV1 { - g := *tb0 + g := *tb0Signed g.Epoch = 1 return &g }(), @@ -356,14 +387,14 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend ok", - prev: tb0, - curr: tb1, + prev: tb0Signed, + curr: tb1Signed, }, { name: "extend with different network id nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.NetworkID = b.NetworkID + 1 return &b }(), @@ -371,9 +402,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with same epoch nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.Epoch = 0 return &b }(), @@ -381,9 +412,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with epoch not incremented by 1 nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.Epoch = 2 return &b }(), @@ -391,9 +422,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with same epoch start nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.EpochStart = 5 return &b }(), @@ -401,9 +432,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with smaller epoch start nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.EpochStart = 4 return &b }(), @@ -411,14 +442,182 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with invalid previous hash nok", - prev: tb0, + prev: tb0Signed, curr: func() *RootTrustBaseV1 { - b := *tb1 + b := *tb1Signed b.PreviousEntryHash = []byte{1, 2, 3} return &b }(), wantErr: "previous trust base hash does not match", }, + { + name: "extend without current epoch signatures nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + // sign with previous epoch keys + for i := 1; i <= 3; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + return tb + }(), + wantErr: "failed to verify signatures: quorum not reached, signed_votes=0 quorum_threshold=3", + }, + { + name: "extend without previous epoch signatures nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + // sign with current epoch keys + for i := 1; i <= 3; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + return tb + }(), + wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=0 quorum_threshold=3", + }, + { + name: "extend with not enough previous epoch signatures nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + // sign with current epoch keys + for i := 1; i <= 3; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + // sign with 2 of 3 required previous epoch keys + for i := 1; i <= 2; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + return tb + }(), + wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", + }, + { + name: "extend with not enough current epoch signatures nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + // sign with 2 of 3 current epoch keys + for i := 1; i <= 2; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + // sign with 2 of 3 required previous epoch keys + for i := 1; i <= 2; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + return tb + }(), + wantErr: "failed to verify signatures: quorum not reached, signed_votes=2 quorum_threshold=3", + }, + { + name: "extend with invalid previous epoch signature nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + for i := 1; i <= 3; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + for i := 1; i <= 3; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + tb.PreviousEpochSignatures["1"][0] ^= 0xff // tamper with signature + return tb + }(), + wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", + }, + { + name: "extend with invalid current epoch signature nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + for i := 1; i <= 3; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + for i := 1; i <= 3; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + tb.Signatures["1"][0] ^= 0xff // tamper with signature + return tb + }(), + wantErr: "failed to verify signatures: quorum not reached, signed_votes=2 quorum_threshold=3", + }, + { + name: "extend with signature from node not in previous epoch nok", + prev: tb0Signed, + curr: func() *RootTrustBaseV1 { + tb, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), + WithEpochStart(50), + WithPreviousTrustBaseHash(tb0Hash), + ) + require.NoError(t, err) + + // sign with current epoch keys + for i := 1; i <= 3; i++ { + err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + // sign with 2 of 3 previous epoch keys + for i := 1; i <= 2; i++ { + err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) + require.NoError(t, err) + } + // sign with key that is not in tb0Signed + signer, err := abcrypto.NewInMemorySecp256K1Signer() + require.NoError(t, err) + require.NoError(t, tb.SignPrevious("4", signer)) + + return tb + }(), + wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", + }, } for _, tt := range tests { From dfec80450041a1d93517b095dc1afa577f69c5ab Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Tue, 25 Nov 2025 14:06:12 +0200 Subject: [PATCH 6/8] remove bson tags from root trust base --- types/root_trust_base.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index dcad833..60cf676 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -29,17 +29,17 @@ type ( RootTrustBaseV1 struct { _ struct{} `cbor:",toarray"` - Version Version `json:"version" bson:"version"` - NetworkID NetworkID `json:"networkId" bson:"networkId"` - Epoch uint64 `json:"epoch" bson:"epoch"` // current epoch number - EpochStart uint64 `json:"epochStartRound" bson:"epochStartRound"` // root chain round number when the epoch begins - RootNodes []*NodeInfo `json:"rootNodes" bson:"rootNodes"` // list of all root nodes for the current epoch - QuorumThreshold uint64 `json:"quorumThreshold" bson:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node - StateHash hex.Bytes `json:"stateHash" bson:"stateHash"` // unicity tree root hash - ChangeRecordHash hex.Bytes `json:"changeRecordHash" bson:"changeRecordHash"` // epoch change request hash - PreviousEntryHash hex.Bytes `json:"previousEntryHash" bson:"previousEntryHash"` // previous trust base entry hash - Signatures map[string]hex.Bytes `json:"signatures" bson:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself - PreviousEpochSignatures map[string]hex.Bytes `json:"previousEpochSignatures" bson:"previousEpochSignatures"` // signatures of previous epoch validators, over all fields except for this field itself + Version Version `json:"version"` + NetworkID NetworkID `json:"networkId"` + Epoch uint64 `json:"epoch"` // current epoch number + EpochStart uint64 `json:"epochStartRound"` // root chain round number when the epoch begins + RootNodes []*NodeInfo `json:"rootNodes"` // list of all root nodes for the current epoch + QuorumThreshold uint64 `json:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node + StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash + ChangeRecordHash hex.Bytes `json:"changeRecordHash"` // epoch change request hash + PreviousEntryHash hex.Bytes `json:"previousEntryHash"` // previous trust base entry hash + Signatures map[string]hex.Bytes `json:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself + PreviousEpochSignatures map[string]hex.Bytes `json:"previousEpochSignatures"` // signatures of previous epoch validators, over all fields except for this field itself } NodeInfo struct { From 9545226e4709f7e8326c1eda08efa82d1b189254 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Tue, 25 Nov 2025 15:46:02 +0200 Subject: [PATCH 7/8] sign trust base with only the previous epoch's validators --- types/root_trust_base.go | 88 +++++--------- types/root_trust_base_test.go | 209 +++++++--------------------------- 2 files changed, 69 insertions(+), 228 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index 60cf676..2128b07 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -28,18 +28,17 @@ type ( } RootTrustBaseV1 struct { - _ struct{} `cbor:",toarray"` - Version Version `json:"version"` - NetworkID NetworkID `json:"networkId"` - Epoch uint64 `json:"epoch"` // current epoch number - EpochStart uint64 `json:"epochStartRound"` // root chain round number when the epoch begins - RootNodes []*NodeInfo `json:"rootNodes"` // list of all root nodes for the current epoch - QuorumThreshold uint64 `json:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node - StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash - ChangeRecordHash hex.Bytes `json:"changeRecordHash"` // epoch change request hash - PreviousEntryHash hex.Bytes `json:"previousEntryHash"` // previous trust base entry hash - Signatures map[string]hex.Bytes `json:"signatures"` // signatures of current epoch validators, over all fields except for the signatures fields itself - PreviousEpochSignatures map[string]hex.Bytes `json:"previousEpochSignatures"` // signatures of previous epoch validators, over all fields except for this field itself + _ struct{} `cbor:",toarray"` + Version Version `json:"version"` + NetworkID NetworkID `json:"networkId"` + Epoch uint64 `json:"epoch"` // current epoch number + EpochStart uint64 `json:"epochStartRound"` // root chain round number when the epoch begins + RootNodes []*NodeInfo `json:"rootNodes"` // list of all root nodes for the current epoch + QuorumThreshold uint64 `json:"quorumThreshold"` // amount of coins required to reach consensus, currently each node gets equal amount of voting power i.e. +1 for each node + StateHash hex.Bytes `json:"stateHash"` // unicity tree root hash + ChangeRecordHash hex.Bytes `json:"changeRecordHash"` // epoch change request hash + PreviousEntryHash hex.Bytes `json:"previousEntryHash"` // previous trust base entry hash + Signatures map[string]hex.Bytes `json:"signatures"` // signatures of previous epoch validators, over all fields except for the signatures fields itself } NodeInfo struct { @@ -190,29 +189,6 @@ func (r *RootTrustBaseV1) Sign(nodeID string, signer abcrypto.Signer) error { return nil } -// SignPrevious signs the trust base entry, storing the signature to PreviousEpochSignatures map. -func (r *RootTrustBaseV1) SignPrevious(nodeID string, signer abcrypto.Signer) error { - if nodeID == "" { - return errors.New("node identifier is empty") - } - if signer == nil { - return errors.New("signer is nil") - } - sb, err := r.PreviousEpochSigBytes() - if err != nil { - return err - } - sig, err := signer.SignBytes(sb) - if err != nil { - return fmt.Errorf("signing failed: %w", err) - } - if r.PreviousEpochSignatures == nil { - r.PreviousEpochSignatures = make(map[string]hex.Bytes) - } - r.PreviousEpochSignatures[nodeID] = sig - return nil -} - // Hash hashes the entire structure including the signatures. func (r *RootTrustBaseV1) Hash(hashAlgo crypto.Hash) ([]byte, error) { hasher := abhash.New(hashAlgo.New()) @@ -220,20 +196,9 @@ func (r *RootTrustBaseV1) Hash(hashAlgo crypto.Hash) ([]byte, error) { return hasher.Sum() } -// SigBytes serializes all fields expect for the Signatures and PreviousEpochSignatures fields. +// SigBytes serializes all fields expect for the Signatures field itself. func (r RootTrustBaseV1) SigBytes() ([]byte, error) { r.Signatures = nil - r.PreviousEpochSignatures = nil - bs, err := r.MarshalCBOR() - if err != nil { - return nil, fmt.Errorf("failed to marshal root trust base: %w", err) - } - return bs, nil -} - -// PreviousEpochSigBytes serializes all fields expect for the PreviousEpochSignatures field. -func (r RootTrustBaseV1) PreviousEpochSigBytes() ([]byte, error) { - r.PreviousEpochSignatures = nil bs, err := r.MarshalCBOR() if err != nil { return nil, fmt.Errorf("failed to marshal root trust base: %w", err) @@ -382,26 +347,25 @@ func (r *RootTrustBaseV1) IsValid(prev *RootTrustBaseV1) error { return nil } -// VerifySignatures verifies the trust base is signed by quorum. +// VerifySignatures verifies that the trust base is signed by the previous +// epoch's validators. For the genesis trust base (epoch 0), the trust base +// must be self-signed by the genesis (epoch 0) validators. func (r *RootTrustBaseV1) VerifySignatures(prev *RootTrustBaseV1) error { - // verify current epoch signatures sigBytes, err := r.SigBytes() if err != nil { - return fmt.Errorf("failed to get sig bytes: %w", err) + return fmt.Errorf("failed to get previous epoch sig bytes: %w", err) + } + var tb *RootTrustBaseV1 + if r.Epoch == 0 { + tb = r + } else { + if prev == nil { + return errors.New("previous trust base is nil") + } + tb = prev } - if err := r.VerifyQuorumSignatures(sigBytes, r.Signatures); err != nil { + if err := tb.VerifyQuorumSignatures(sigBytes, r.Signatures); err != nil { return fmt.Errorf("failed to verify signatures: %w", err) } - - // verify previous epoch signatures - if prev != nil { - prevSigBytes, err := r.PreviousEpochSigBytes() - if err != nil { - return fmt.Errorf("failed to get previous epoch sig bytes: %w", err) - } - if err := prev.VerifyQuorumSignatures(prevSigBytes, r.PreviousEpochSignatures); err != nil { - return fmt.Errorf("failed to verify previous epoch signatures: %w", err) - } - } return nil } diff --git a/types/root_trust_base_test.go b/types/root_trust_base_test.go index c775f2e..86bb780 100644 --- a/types/root_trust_base_test.go +++ b/types/root_trust_base_test.go @@ -314,7 +314,8 @@ func NewTrustBaseFromVerifiers(t *testing.T, verifiers map[string]abcrypto.Verif } func TestRootTrustBaseV1_Verify(t *testing.T) { - keys := genKeys(4) + // epoch 0 = nodes 1-3 + keys := genKeys(3) nodes := make([]*NodeInfo, 0, len(keys)) for i := 1; i <= len(keys); i++ { nodeID := strconv.Itoa(i) @@ -322,26 +323,31 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { } // create trust base for epoch 0 - tb0Signed, err := NewTrustBase(NetworkLocal, nodes, WithEpoch(0), WithEpochStart(5)) + tb0Signed, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(0), + WithEpochStart(5), + ) require.NoError(t, err) require.EqualValues(t, 3, tb0Signed.QuorumThreshold) // sign trust base for epoch 0 for i := 1; i <= 3; i++ { - err := tb0Signed.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) + nodeID := strconv.Itoa(i) + require.NoError(t, tb0Signed.Sign(nodeID, keys[nodeID].signer)) } - // create unsigned trust base for epoch 0 - tb0Unsigned, err := NewTrustBase(NetworkLocal, nodes, WithEpoch(0), WithEpochStart(5)) - require.NoError(t, err) - // calculate signed trust base hash tb0Hash, err := tb0Signed.Hash(crypto.SHA256) require.NoError(t, err) - // create a valid trust base for epoch 1, signed by both previous and current validators - tb1Signed, err := NewTrustBase(NetworkLocal, nodes, + // create a valid trust base for epoch 1, signed by previous validators + keys1 := genKeys(3) + nodes1 := make([]*NodeInfo, 0, len(keys1)) + for i := 1 + 10; i <= len(keys)+10; i++ { + nodeID := strconv.Itoa(i) + nodes1 = append(nodes1, &NodeInfo{NodeID: nodeID, SigKey: keys[nodeID].publicKey, Stake: 1}) + } + tb1Signed, err := NewTrustBase(NetworkLocal, nodes1, WithEpoch(1), WithEpochStart(50), WithPreviousTrustBaseHash(tb0Hash), @@ -349,13 +355,10 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { require.NoError(t, err) require.EqualValues(t, 3, tb0Signed.QuorumThreshold) + // sign tb1 with previous epoch keys for i := 1; i <= 3; i++ { - err := tb1Signed.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - for i := 1; i <= 3; i++ { - err = tb1Signed.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) + nodeID := strconv.Itoa(i) + require.NoError(t, tb1Signed.Sign(nodeID, keys[nodeID].signer)) } tests := []struct { @@ -365,18 +368,26 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr string }{ { - name: "genesis trust base with epoch zero ok", + name: "genesis trust base with epoch zero", prev: nil, curr: tb0Signed, }, { - name: "genesis trust base without signatures nok", - prev: nil, - curr: tb0Unsigned, + name: "genesis trust base without signatures", + prev: nil, + curr: func() *RootTrustBaseV1 { + // create unsigned trust base for epoch 0 + tb0Unsigned, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(0), + WithEpochStart(5), + ) + require.NoError(t, err) + return tb0Unsigned + }(), wantErr: "failed to verify signatures: quorum not reached, signed_votes=0 quorum_threshold=3", }, { - name: "genesis trust base with non-zero epoch nok", + name: "genesis trust base with non-zero epoch", prev: nil, curr: func() *RootTrustBaseV1 { g := *tb0Signed @@ -386,12 +397,12 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "genesis trust base epoch must be 0, got 1", }, { - name: "extend ok", + name: "extend", prev: tb0Signed, curr: tb1Signed, }, { - name: "extend with different network id nok", + name: "extend with different network id", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -401,7 +412,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "invalid network id, got 4 previous 3", }, { - name: "extend with same epoch nok", + name: "extend with same epoch", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -411,7 +422,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "invalid epoch, got 0 previous 0", }, { - name: "extend with epoch not incremented by 1 nok", + name: "extend with epoch not incremented by 1", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -421,7 +432,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "invalid epoch, got 2 previous 0", }, { - name: "extend with same epoch start nok", + name: "extend with same epoch start", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -431,7 +442,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "invalid epoch start, got 5 previous 5", }, { - name: "extend with smaller epoch start nok", + name: "extend with smaller epoch start", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -441,7 +452,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "invalid epoch start, got 4 previous 5", }, { - name: "extend with invalid previous hash nok", + name: "extend with invalid previous hash", prev: tb0Signed, curr: func() *RootTrustBaseV1 { b := *tb1Signed @@ -451,7 +462,7 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { wantErr: "previous trust base hash does not match", }, { - name: "extend without current epoch signatures nok", + name: "extend without previous epoch signatures", prev: tb0Signed, curr: func() *RootTrustBaseV1 { tb, err := NewTrustBase(NetworkLocal, nodes, @@ -460,38 +471,12 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { WithPreviousTrustBaseHash(tb0Hash), ) require.NoError(t, err) - - // sign with previous epoch keys - for i := 1; i <= 3; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } return tb }(), wantErr: "failed to verify signatures: quorum not reached, signed_votes=0 quorum_threshold=3", }, { - name: "extend without previous epoch signatures nok", - prev: tb0Signed, - curr: func() *RootTrustBaseV1 { - tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), - WithEpochStart(50), - WithPreviousTrustBaseHash(tb0Hash), - ) - require.NoError(t, err) - - // sign with current epoch keys - for i := 1; i <= 3; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - return tb - }(), - wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=0 quorum_threshold=3", - }, - { - name: "extend with not enough previous epoch signatures nok", + name: "extend with not enough previous epoch signatures", prev: tb0Signed, curr: func() *RootTrustBaseV1 { tb, err := NewTrustBase(NetworkLocal, nodes, @@ -501,123 +486,15 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { ) require.NoError(t, err) - // sign with current epoch keys - for i := 1; i <= 3; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } // sign with 2 of 3 required previous epoch keys for i := 1; i <= 2; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - return tb - }(), - wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", - }, - { - name: "extend with not enough current epoch signatures nok", - prev: tb0Signed, - curr: func() *RootTrustBaseV1 { - tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), - WithEpochStart(50), - WithPreviousTrustBaseHash(tb0Hash), - ) - require.NoError(t, err) - - // sign with 2 of 3 current epoch keys - for i := 1; i <= 2; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - // sign with 2 of 3 required previous epoch keys - for i := 1; i <= 2; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) + nodeID := strconv.Itoa(i) + require.NoError(t, tb.Sign(nodeID, keys[nodeID].signer)) } return tb }(), wantErr: "failed to verify signatures: quorum not reached, signed_votes=2 quorum_threshold=3", }, - { - name: "extend with invalid previous epoch signature nok", - prev: tb0Signed, - curr: func() *RootTrustBaseV1 { - tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), - WithEpochStart(50), - WithPreviousTrustBaseHash(tb0Hash), - ) - require.NoError(t, err) - - for i := 1; i <= 3; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - for i := 1; i <= 3; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - tb.PreviousEpochSignatures["1"][0] ^= 0xff // tamper with signature - return tb - }(), - wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", - }, - { - name: "extend with invalid current epoch signature nok", - prev: tb0Signed, - curr: func() *RootTrustBaseV1 { - tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), - WithEpochStart(50), - WithPreviousTrustBaseHash(tb0Hash), - ) - require.NoError(t, err) - - for i := 1; i <= 3; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - for i := 1; i <= 3; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - tb.Signatures["1"][0] ^= 0xff // tamper with signature - return tb - }(), - wantErr: "failed to verify signatures: quorum not reached, signed_votes=2 quorum_threshold=3", - }, - { - name: "extend with signature from node not in previous epoch nok", - prev: tb0Signed, - curr: func() *RootTrustBaseV1 { - tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), - WithEpochStart(50), - WithPreviousTrustBaseHash(tb0Hash), - ) - require.NoError(t, err) - - // sign with current epoch keys - for i := 1; i <= 3; i++ { - err := tb.Sign(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - // sign with 2 of 3 previous epoch keys - for i := 1; i <= 2; i++ { - err := tb.SignPrevious(strconv.Itoa(i), keys[strconv.Itoa(i)].signer) - require.NoError(t, err) - } - // sign with key that is not in tb0Signed - signer, err := abcrypto.NewInMemorySecp256K1Signer() - require.NoError(t, err) - require.NoError(t, tb.SignPrevious("4", signer)) - - return tb - }(), - wantErr: "failed to verify previous epoch signatures: quorum not reached, signed_votes=2 quorum_threshold=3", - }, } for _, tt := range tests { From 7ba32481c011a3b3f526f38d8860d15e3fef8134 Mon Sep 17 00:00:00 2001 From: Lennart Ploom Date: Mon, 29 Dec 2025 11:32:50 +0200 Subject: [PATCH 8/8] require genesis trust base epoch to be equal to 1 --- types/root_trust_base.go | 14 +++--- types/root_trust_base_test.go | 92 +++++++++++++++++------------------ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/types/root_trust_base.go b/types/root_trust_base.go index 2128b07..3db8c1c 100644 --- a/types/root_trust_base.go +++ b/types/root_trust_base.go @@ -69,7 +69,7 @@ func NewTrustBase(networkID NetworkID, rootNodes []*NodeInfo, opts ...Option) (* } // init config - c := &trustBaseConf{} + c := &trustBaseConf{epoch: 1} for _, opt := range opts { opt(c) } @@ -304,7 +304,7 @@ func (r *RootTrustBaseV1) getRootNode(nodeID string) *NodeInfo { // - The current epoch signatures must be valid and reach quorum. // // Genesis trust base: -// - Epoch must be zero. +// - Epoch must be equal to 1. // // Non-genesis trust base must extend previous trust base: // - The network identifiers must match. @@ -323,8 +323,8 @@ func (r *RootTrustBaseV1) Verify(prev *RootTrustBaseV1) error { // Use VerifySignatures to verify the signatures. func (r *RootTrustBaseV1) IsValid(prev *RootTrustBaseV1) error { if prev == nil { - if r.Epoch != 0 { - return fmt.Errorf("genesis trust base epoch must be 0, got %d", r.Epoch) + if r.Epoch != 1 { + return fmt.Errorf("genesis trust base epoch must be 1, got %d", r.Epoch) } return nil } @@ -348,15 +348,15 @@ func (r *RootTrustBaseV1) IsValid(prev *RootTrustBaseV1) error { } // VerifySignatures verifies that the trust base is signed by the previous -// epoch's validators. For the genesis trust base (epoch 0), the trust base -// must be self-signed by the genesis (epoch 0) validators. +// epoch's validators. For the genesis trust base (epoch 1), the trust base +// must be self-signed by the genesis (epoch 1) validators. func (r *RootTrustBaseV1) VerifySignatures(prev *RootTrustBaseV1) error { sigBytes, err := r.SigBytes() if err != nil { return fmt.Errorf("failed to get previous epoch sig bytes: %w", err) } var tb *RootTrustBaseV1 - if r.Epoch == 0 { + if r.Epoch == 1 { tb = r } else { if prev == nil { diff --git a/types/root_trust_base_test.go b/types/root_trust_base_test.go index 86bb780..20dd4d5 100644 --- a/types/root_trust_base_test.go +++ b/types/root_trust_base_test.go @@ -74,7 +74,7 @@ func TestNewTrustBaseGenesis(t *testing.T) { }, verifyFunc: func(t *testing.T, tb *RootTrustBaseV1) { // verify values - require.EqualValues(t, 0, tb.Epoch) + require.EqualValues(t, 1, tb.Epoch) require.EqualValues(t, 0, tb.EpochStart) require.Len(t, tb.RootNodes, 3) require.EqualValues(t, 3, tb.QuorumThreshold) @@ -314,7 +314,7 @@ func NewTrustBaseFromVerifiers(t *testing.T, verifiers map[string]abcrypto.Verif } func TestRootTrustBaseV1_Verify(t *testing.T) { - // epoch 0 = nodes 1-3 + // epoch 1 = nodes 1-3 keys := genKeys(3) nodes := make([]*NodeInfo, 0, len(keys)) for i := 1; i <= len(keys); i++ { @@ -322,43 +322,43 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { nodes = append(nodes, &NodeInfo{NodeID: nodeID, SigKey: keys[nodeID].publicKey, Stake: 1}) } - // create trust base for epoch 0 - tb0Signed, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(0), + // create trust base for epoch 1 + tb1Signed, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), WithEpochStart(5), ) require.NoError(t, err) - require.EqualValues(t, 3, tb0Signed.QuorumThreshold) + require.EqualValues(t, 3, tb1Signed.QuorumThreshold) - // sign trust base for epoch 0 + // sign trust base for epoch 1 for i := 1; i <= 3; i++ { nodeID := strconv.Itoa(i) - require.NoError(t, tb0Signed.Sign(nodeID, keys[nodeID].signer)) + require.NoError(t, tb1Signed.Sign(nodeID, keys[nodeID].signer)) } // calculate signed trust base hash - tb0Hash, err := tb0Signed.Hash(crypto.SHA256) + tb0Hash, err := tb1Signed.Hash(crypto.SHA256) require.NoError(t, err) - // create a valid trust base for epoch 1, signed by previous validators + // create a valid trust base for epoch 2, signed by previous validators keys1 := genKeys(3) nodes1 := make([]*NodeInfo, 0, len(keys1)) for i := 1 + 10; i <= len(keys)+10; i++ { nodeID := strconv.Itoa(i) nodes1 = append(nodes1, &NodeInfo{NodeID: nodeID, SigKey: keys[nodeID].publicKey, Stake: 1}) } - tb1Signed, err := NewTrustBase(NetworkLocal, nodes1, - WithEpoch(1), + tb2Signed, err := NewTrustBase(NetworkLocal, nodes1, + WithEpoch(2), WithEpochStart(50), WithPreviousTrustBaseHash(tb0Hash), ) require.NoError(t, err) - require.EqualValues(t, 3, tb0Signed.QuorumThreshold) + require.EqualValues(t, 3, tb1Signed.QuorumThreshold) - // sign tb1 with previous epoch keys + // sign tb2 with previous epoch keys for i := 1; i <= 3; i++ { nodeID := strconv.Itoa(i) - require.NoError(t, tb1Signed.Sign(nodeID, keys[nodeID].signer)) + require.NoError(t, tb2Signed.Sign(nodeID, keys[nodeID].signer)) } tests := []struct { @@ -370,42 +370,42 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { { name: "genesis trust base with epoch zero", prev: nil, - curr: tb0Signed, + curr: tb1Signed, }, { name: "genesis trust base without signatures", prev: nil, curr: func() *RootTrustBaseV1 { - // create unsigned trust base for epoch 0 - tb0Unsigned, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(0), + // create unsigned trust base for epoch 1 + tb1Unsigned, err := NewTrustBase(NetworkLocal, nodes, + WithEpoch(1), WithEpochStart(5), ) require.NoError(t, err) - return tb0Unsigned + return tb1Unsigned }(), wantErr: "failed to verify signatures: quorum not reached, signed_votes=0 quorum_threshold=3", }, { - name: "genesis trust base with non-zero epoch", + name: "genesis trust base with zero epoch", prev: nil, curr: func() *RootTrustBaseV1 { - g := *tb0Signed - g.Epoch = 1 + g := *tb1Signed + g.Epoch = 0 return &g }(), - wantErr: "genesis trust base epoch must be 0, got 1", + wantErr: "genesis trust base epoch must be 1, got 0", }, { name: "extend", - prev: tb0Signed, - curr: tb1Signed, + prev: tb1Signed, + curr: tb2Signed, }, { name: "extend with different network id", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed + b := *tb2Signed b.NetworkID = b.NetworkID + 1 return &b }(), @@ -413,29 +413,29 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with same epoch", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed - b.Epoch = 0 + b := *tb2Signed + b.Epoch = 1 return &b }(), - wantErr: "invalid epoch, got 0 previous 0", + wantErr: "invalid epoch, got 1 previous 1", }, { name: "extend with epoch not incremented by 1", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed - b.Epoch = 2 + b := *tb2Signed + b.Epoch = 3 return &b }(), - wantErr: "invalid epoch, got 2 previous 0", + wantErr: "invalid epoch, got 3 previous 1", }, { name: "extend with same epoch start", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed + b := *tb2Signed b.EpochStart = 5 return &b }(), @@ -443,9 +443,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with smaller epoch start", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed + b := *tb2Signed b.EpochStart = 4 return &b }(), @@ -453,9 +453,9 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with invalid previous hash", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { - b := *tb1Signed + b := *tb2Signed b.PreviousEntryHash = []byte{1, 2, 3} return &b }(), @@ -463,10 +463,10 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend without previous epoch signatures", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), + WithEpoch(2), WithEpochStart(50), WithPreviousTrustBaseHash(tb0Hash), ) @@ -477,10 +477,10 @@ func TestRootTrustBaseV1_Verify(t *testing.T) { }, { name: "extend with not enough previous epoch signatures", - prev: tb0Signed, + prev: tb1Signed, curr: func() *RootTrustBaseV1 { tb, err := NewTrustBase(NetworkLocal, nodes, - WithEpoch(1), + WithEpoch(2), WithEpochStart(50), WithPreviousTrustBaseHash(tb0Hash), )