Merged
Conversation
- Initialize go module as github.com/uts-dot/sdk-go - Add go-ethereum v1.17.1 dependency - Add package documentation in doc.go
Add comprehensive error types for the Go SDK: - ErrorCode type and constants for all error variants - SDKError struct with Code, Message, and Context - DecodeError with constructors for all variants (BadMagic, BadVersion, LEB128Overflow, BadOpCode, etc.) - EncodeError with constructors (UsizeOverflow, InvalidUriChar, UriTooLong) - VerifyError with constructors (NoValue, Pending, BadAttestationTag, Decode) - EASVerifierError with constructors and IsFatal/ShouldRetry methods - RemoteError for network/remote operation failures
Define core timestamp types for Go SDK: - Op type with all operation constants (APPEND, PREPEND, SHA256, etc.) - Step interface with Op() method - Concrete step types: AppendStep, PrependStep, ReverseStep, HexlifyStep - Digest step types: SHA256Step, Keccak256Step, SHA1Step, RIPEMD160Step - ForkStep with nested Timestamp slice - AttestationStep wrapping Attestation interface - Timestamp as []Step slice
- Define DigestOp constants with output sizes (SHA1/RIPEMD160: 20 bytes, SHA256/KECCAK256: 32 bytes) - Define DigestHeader with Kind and Digest fields - Define DetachedTimestamp with Header and Timestamp - Define AttestationStatusKind constants: VALID, INVALID, PENDING, UNKNOWN - Define AttestationStatus with attestation, status, error, and info fields - Define VerifyStatus constants: VALID, PARTIAL_VALID, INVALID, PENDING - Define UpgradeStatus constants: UPGRADED, PENDING, FAILED - Define UpgradeResult and VerificationResult structs
Add encoder with methods for writing bytes, LEB128 integers, headers, steps (append/prepend/hash/fork/attestation), and full timestamps.
Add crypto package with hash function wrappers for the UTS protocol. Includes SHA256 using standard library and Keccak256 using go-ethereum.
Add EthereumClient for connecting to Ethereum RPC endpoints and interacting with EAS contracts. Includes chain-specific address configuration and contract call methods for attestation and timestamp retrieval.
- Add VerifyBitcoin function with RPC client interface - Implement merkle root comparison with byte reversal - Add comprehensive test coverage for success and error cases - Create package documentation explaining Bitcoin verification process
- Add VerifyEASAttestation for validating EAS attestations - Add VerifyEASTimestamped for timestamp-based verification - Verify schema ID matches UTS schema - Check attestation is not revocable - Validate attested hash matches expected digest - Include comprehensive tests for all verification paths
- Create sdk.go with SDK struct, options, and core methods - Implement Stamp: generates nonces, builds Merkle tree, submits to calendars - Implement Verify: executes steps and verifies attestations - Implement Upgrade: upgrades pending attestations from calendars - Move errors to separate package to break import cycle - Update codec package imports to use new errors package
- Add tests for SDK constructor and options (NewSDK, WithCalendars, WithBitcoinRPC, WithEthereumRPC, WithTimeout, WithQuorum, WithNonceSize, WithHashAlgorithm) - Add tests for Stamp method with mock calendar server - Add tests for Verify method with various attestation types (pending, bitcoin, unknown) - Add tests for Upgrade method with mock upgrade server - Add tests for executeStep helper (AppendStep, PrependStep, ReverseStep, HexlifyStep, SHA256Step, Keccak256Step) - Add tests for aggregateResult helper - Add tests for edge cases (context cancellation, invalid URLs, malformed responses) - Add tests for VerificationResult - Test coverage: 76.9% for SDK package
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Go SDK (packages/sdk-go) for the Universal Timestamps (UTS) protocol, including core timestamp types, encoding/decoding, cryptographic primitives, attestation verification, an HTTP-based SDK client, and runnable examples.
Changes:
- Add
uts.SDKwith Stamp/Verify/Upgrade workflows, calendar communication, and quorum handling. - Implement UTS/OpenTimestamps-compatible codec (encoder/decoder, LEB128), crypto (hashes + Merkle tree), and RPC helpers.
- Add types + attestation verification logic, documentation, examples, and extensive tests.
Reviewed changes
Copilot reviewed 41 out of 42 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/sdk-go/types/timestamp_test.go | Tests for opcode/step/timestamp primitives. |
| packages/sdk-go/types/timestamp.go | Defines ops/steps/timestamp structures and formatting. |
| packages/sdk-go/types/status.go | Verification/upgrade status types and helpers. |
| packages/sdk-go/types/header_test.go | Tests for digest header and detached timestamp. |
| packages/sdk-go/types/header.go | Digest header + detached timestamp types. |
| packages/sdk-go/types/doc.go | Package documentation for timestamp types. |
| packages/sdk-go/types/attestation_test.go | Tests for attestation types and URI validation. |
| packages/sdk-go/types/attestation.go | Attestation types (Bitcoin, EAS, pending, unknown) + URI validation. |
| packages/sdk-go/sdk_test.go | End-to-end and unit tests for SDK behaviors. |
| packages/sdk-go/sdk.go | Core SDK implementation: stamping, verifying, upgrading. |
| packages/sdk-go/rpc/ethereum.go | Ethereum RPC client wrapper for EAS contract calls. |
| packages/sdk-go/rpc/doc.go | RPC package documentation. |
| packages/sdk-go/rpc/bitcoin.go | Bitcoin JSON-RPC client + byte-reversal utilities. |
| packages/sdk-go/go.mod | Go module definition and dependencies. |
| packages/sdk-go/examples/verify/main.go | Example CLI for verifying a timestamp file. |
| packages/sdk-go/examples/upgrade/main.go | Example CLI for upgrading pending attestations. |
| packages/sdk-go/examples/stamp/main.go | Example CLI for stamping a file/sample data. |
| packages/sdk-go/errors/errors.go | Structured SDK error types and constructors. |
| packages/sdk-go/errors.go | Re-exports error codes/types at top-level package. |
| packages/sdk-go/doc.go | Top-level SDK package documentation. |
| packages/sdk-go/crypto/hash_test.go | Tests for SHA256/Keccak256 wrappers. |
| packages/sdk-go/crypto/hash.go | Hash wrappers (SHA256, Keccak256) used across SDK. |
| packages/sdk-go/crypto/doc.go | Crypto package documentation. |
| packages/sdk-go/crypto/bmt_test.go | Tests for Merkle tree construction/proofs/serialization. |
| packages/sdk-go/crypto/bmt.go | Merkle tree implementation + proof generation/verification. |
| packages/sdk-go/codec/leb128_test.go | Tests for LEB128 encode/decode helpers. |
| packages/sdk-go/codec/leb128.go | LEB128 encoding/decoding implementation. |
| packages/sdk-go/codec/encoder_test.go | Tests for encoding headers/steps/timestamps. |
| packages/sdk-go/codec/encoder.go | Timestamp encoder implementation. |
| packages/sdk-go/codec/doc.go | Codec package documentation. |
| packages/sdk-go/codec/decoder_test.go | Tests for decoding timestamps and error handling. |
| packages/sdk-go/codec/decoder.go | Timestamp decoder implementation. |
| packages/sdk-go/codec/constants.go | Codec constants (magic bytes, opcodes, tags). |
| packages/sdk-go/attestation/verify_test.go | Tests for attestation verification dispatcher. |
| packages/sdk-go/attestation/verify.go | Attestation verification dispatcher. |
| packages/sdk-go/attestation/eas_test.go | Tests for EAS attestation verification. |
| packages/sdk-go/attestation/eas.go | EAS verification logic (schema, revocable, data checks). |
| packages/sdk-go/attestation/doc.go | Attestation package documentation. |
| packages/sdk-go/attestation/bitcoin_test.go | Tests for Bitcoin attestation verification. |
| packages/sdk-go/attestation/bitcoin.go | Bitcoin verification logic against block headers. |
| packages/sdk-go/README.md | SDK README with install + usage overview. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 49 out of 50 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (9)
packages/sdk-go/sdk.go:1
calendars: DefaultCalendarsassigns the global slice directly, and the subsequent in-place normalization mutates the underlying array—effectively modifying the package-levelDefaultCalendarsat runtime. Clone the slice when initializing the SDK (e.g., copy into a new slice) before normalizing.
packages/sdk-go/sdk.go:1- The “too large” detection can’t work as written:
io.ReadAlltypically returnserr == nilwhen it reaches EOF, including when reading from anio.LimitReader. This means oversized responses will be truncated to 1MB and treated as valid input (likely leading to confusing decode errors or partial parsing). Readlimit+1bytes and error if more thanlimitbytes are present, or use an approach that can reliably detect truncation.
packages/sdk-go/sdk.go:1 - Same truncation/oversize detection issue as in
requestAttestation: the code won’t reliably detect that the response exceeded the 1MB limit. Use alimit+1read or another mechanism that can distinguish “exactly limit bytes read” from “response ended within limit.”
packages/sdk-go/sdk.go:1 AddChainreturns anerror, but it’s ignored here, so RPC misconfiguration or dial failures become silent and can surface later as “no client configured” / unexpected verification failures. Consider changing the option/config pattern soNewSDKcan surface initialization failures (e.g.,Option func(*SDK) errorandNewSDK(...)(*SDK, error)), or makeAddChainlazy (store URL now, dial on first use) and log/record the error deterministically when dialing fails.
packages/sdk-go/types/header.go:1dt.Timestampis atypes.Timestamp(a slice), but the format string uses%s. This will produce"%!s(...)"output instead of a meaningful timestamp string. Either implementfunc (t Timestamp) String() stringand use%swith it, or change formatting to%vand format steps explicitly.
packages/sdk-go/types/header.go:1DigestBytes()returns the internal slice, allowing callers to mutate the header digest after construction (even thoughNewDigestHeadercopies the input). To preserve immutability and prevent subtle bugs, return a defensive copy (or document clearly that the returned slice must be treated as read-only).
packages/sdk-go/sdk.go:1- Returning the internal slice allows callers to mutate SDK configuration (calendars) without using options, which can lead to hard-to-track behavior (and potential data races if used concurrently). Return a copy of the slice to keep the SDK state encapsulated.
packages/sdk-go/sdk.go:1 - These branches return plain
fmt.Errorferrors, whileexecuteStepreturns structurederrors.SDErrorfor unsupported algorithms. This inconsistency makes error handling harder for SDK consumers. Prefer returning the same structured error type (e.g.,errors.NewSDKError(errors.ErrCodeUnsupported, "...", nil)) in all unsupported-hash paths.
packages/sdk-go/sdk.go:1 - The HTTP request/response handling (especially response size limiting and non-200 status handling) is security/robustness-sensitive but currently has no unit tests in this PR. Add tests using
httptest.Serverto cover: (1) oversized response (>1MB) correctly detected, (2) exact-limit response, (3) non-200 responses, and (4) invalid timestamp bytes returning an expected decode error.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.