From bdd53a145dc5f446ad0c58c581f7f79551ba85f6 Mon Sep 17 00:00:00 2001 From: PJ Date: Mon, 9 Oct 2023 16:21:49 +0200 Subject: [PATCH] all: upgrade core --- build/network_testing.go | 9 +- cmd/hostd/main.go | 5 +- go.mod | 27 +--- go.sum | 63 +-------- host/contracts/actions.go | 2 +- internal/chain/manager.go | 6 +- internal/test/miner.go | 2 +- internal/test/renter.go | 41 +++--- internal/test/rhp/v2/rhp.go | 264 +++++++++++++++++++++++++----------- rhp/v2/contracts.go | 144 -------------------- rhp/v2/rpc.go | 23 +++- rhp/v2/rpc_test.go | 49 +++++-- wallet/wallet.go | 13 +- 13 files changed, 290 insertions(+), 358 deletions(-) diff --git a/build/network_testing.go b/build/network_testing.go index 42ef3b01..78ff4e61 100644 --- a/build/network_testing.go +++ b/build/network_testing.go @@ -35,8 +35,13 @@ func Network() (*consensus.Network, types.Block) { n.HardforkASIC.OakTarget = types.BlockID{255, 255} n.HardforkFoundation.Height = 50 - n.HardforkFoundation.PrimaryAddress = types.GeneratePrivateKey().PublicKey().StandardAddress() - n.HardforkFoundation.FailsafeAddress = types.GeneratePrivateKey().PublicKey().StandardAddress() + n.HardforkFoundation.PrimaryAddress = types.StandardUnlockHash(types.GeneratePrivateKey().PublicKey()) + n.HardforkFoundation.FailsafeAddress = types.StandardUnlockHash(types.GeneratePrivateKey().PublicKey()) + + // make it difficult to reach v2 in most tests + n.HardforkV2.AllowHeight = 1000 + n.HardforkV2.RequireHeight = 1020 + return n, types.Block{ Transactions: []types.Transaction{ { diff --git a/cmd/hostd/main.go b/cmd/hostd/main.go index f1745b36..5c43be60 100644 --- a/cmd/hostd/main.go +++ b/cmd/hostd/main.go @@ -15,6 +15,7 @@ import ( "syscall" "time" + "go.sia.tech/core/types" "go.sia.tech/core/wallet" "go.sia.tech/hostd/api" "go.sia.tech/hostd/build" @@ -114,7 +115,7 @@ func mustGetSeedPhrase(log *zap.Logger) string { fmt.Println("You will need to re-enter this seed phrase every time you start hostd.") fmt.Println("") fmt.Println("\033[34;1mSeed Phrase:\033[0m", phrase) - fmt.Println("\033[34;1mWallet Address:\033[0m", key.PublicKey().StandardAddress()) + fmt.Println("\033[34;1mWallet Address:\033[0m", types.StandardUnlockHash(key.PublicKey())) // confirm seed phrase for { @@ -240,7 +241,7 @@ func main() { } key := wallet.KeyFromSeed(&seed, 0) fmt.Println("Recovery Phrase:", phrase) - fmt.Println("Address", key.PublicKey().StandardAddress()) + fmt.Println("Address", types.StandardUnlockHash(key.PublicKey())) return } diff --git a/go.mod b/go.mod index 8bbbba22..2f24793f 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.5 github.com/mattn/go-sqlite3 v1.14.17 gitlab.com/NebulousLabs/encoding v0.0.0-20200604091946-456c3dc907fe - go.sia.tech/core v0.1.12-0.20230529164041-6347a98003be + go.sia.tech/core v0.1.12-0.20231011160830-b58e9e8ec3ce go.sia.tech/jape v0.9.1-0.20230525021720-ecf031ecbffb go.sia.tech/renterd v0.6.0 go.sia.tech/siad v1.5.10-0.20230228235644-3059c0b930ca @@ -25,29 +25,18 @@ require ( require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/benbjohnson/clock v1.3.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/dchest/threefish v0.0.0-20120919164726-3ecf4c494abf // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/gotd/contrib v0.19.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/klauspost/reedsolomon v1.11.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - github.com/montanaflynn/stats v0.7.1 // indirect github.com/pkg/errors v0.9.1 // indirect gitlab.com/NebulousLabs/bolt v1.4.4 // indirect gitlab.com/NebulousLabs/demotemutex v0.0.0-20151003192217-235395f71c40 // indirect @@ -62,15 +51,6 @@ require ( gitlab.com/NebulousLabs/ratelimit v0.0.0-20200811080431-99b8f0768b2e // indirect gitlab.com/NebulousLabs/siamux v0.0.2-0.20220630142132-142a1443a259 // indirect gitlab.com/NebulousLabs/threadgroup v0.0.0-20200608151952-38921fbef213 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.sia.tech/mux v1.2.0 // indirect go.sia.tech/web v0.0.0-20230817201630-c3d9328334b1 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -78,10 +58,5 @@ require ( golang.org/x/net v0.15.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.13.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/grpc v1.57.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gorm.io/gorm v1.25.4 // indirect ) diff --git a/go.sum b/go.sum index 54c2d6c2..be5e5138 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,6 @@ github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.75.0 h1:03a4EkwwsDo0yAHjQ/l+D36K9wTkvr0afDiI/uHQ0Xw= @@ -34,11 +32,7 @@ github.com/dchest/threefish v0.0.0-20120919164726-3ecf4c494abf/go.mod h1:bXVurdT github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -47,11 +41,6 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -71,21 +60,17 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -95,13 +80,9 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gotd/contrib v0.19.0 h1:O6GvMrRVeFslIHLUcpaHVzcl9/5PcgR2jQTIIeTyds0= -github.com/gotd/contrib v0.19.0/go.mod h1:LzPxzRF0FvtpBt/WyODWQnPpk0tm/G9z6RHUoPqMakU= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok= github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -115,10 +96,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -144,7 +121,7 @@ github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 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= @@ -165,8 +142,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= -github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -185,7 +160,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -249,26 +224,8 @@ gitlab.com/NebulousLabs/threadgroup v0.0.0-20200608151952-38921fbef213 h1:owERlK gitlab.com/NebulousLabs/threadgroup v0.0.0-20200608151952-38921fbef213/go.mod h1:vIutAvl7lmJqLVYTCBY5WDdJomP+V74At8LCeEYoH8w= gitlab.com/NebulousLabs/writeaheadlog v0.0.0-20200618142844-c59a90f49130/go.mod h1:SxigdS5Q1ui+OMgGAXt1E/Fg3RB6PvKXMov2O3gvIzs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 h1:iqjq9LAB8aK++sKVcELezzn655JnBNdsDhghU4G/So8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0/go.mod h1:hGXzO5bhhSHZnKvrDaXB82Y9DRFour0Nz/KrBh7reWw= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.sia.tech/core v0.1.12-0.20230529164041-6347a98003be h1:fKfwYsCF5ua3Z/NNdLU+4sS9MM6M4EetMA0V4Y8zPKg= -go.sia.tech/core v0.1.12-0.20230529164041-6347a98003be/go.mod h1:D17UWSn99SEfQnEaR9G9n6Kz9+BwqMoUgZ6Cl424LsQ= +go.sia.tech/core v0.1.12-0.20231011160830-b58e9e8ec3ce h1:rRji+HxWtZEyXAyc/LSqS4HIowcGq3kGQLgjXFPQBk8= +go.sia.tech/core v0.1.12-0.20231011160830-b58e9e8ec3ce/go.mod h1:3EoY+rR78w1/uGoXXVqcYdwSjSJKuEMI5bL7WROA27Q= go.sia.tech/jape v0.9.1-0.20230525021720-ecf031ecbffb h1:yLDEqkqC19E/HgBoq2Uhw9oH3SMNRyeRjZ7Ep4dPKR8= go.sia.tech/jape v0.9.1-0.20230525021720-ecf031ecbffb/go.mod h1:4QqmBB+t3W7cNplXPj++ZqpoUb2PeiS66RLpXmEGap4= go.sia.tech/mux v1.2.0 h1:ofa1Us9mdymBbGMY2XH/lSpY8itFsKIo/Aq8zwe+GHU= @@ -383,19 +340,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 h1:Iveh6tGCJkHAjJgEqUQYGDGgbwmhjoAOz8kO/ajxefY= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 h1:WGq4lvB/mlicysM/dUT3SBvijH4D3sm/Ny1A4wmt2CI= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -409,8 +356,6 @@ 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= -gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= -gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= lukechampine.com/frand v1.4.2 h1:RzFIpOvkMXuPMBb9maa4ND4wjBn71E1Jpf8BzJHMaVw= lukechampine.com/frand v1.4.2/go.mod h1:4S/TM2ZgrKejMcKMbeLjISpJMO+/eZ1zu3vYX9dtj3s= diff --git a/host/contracts/actions.go b/host/contracts/actions.go index f34726fb..1c67d61e 100644 --- a/host/contracts/actions.go +++ b/host/contracts/actions.go @@ -167,7 +167,7 @@ func (cm *ContractManager) handleContractAction(id types.FileContractID, height } // get the proof leaf index - leafIndex := cs.StorageProofLeafIndex(contract.Revision.Filesize, windowStart, contract.Revision.ParentID) + leafIndex := cs.StorageProofLeafIndex(contract.Revision.Filesize, windowStart.ID, contract.Revision.ParentID) sp, err := cm.buildStorageProof(contract.Revision.ParentID, contract.Revision.Filesize, leafIndex) if err != nil { log.Error("failed to build storage proof", zap.Error(err)) diff --git a/internal/chain/manager.go b/internal/chain/manager.go index 2bc7e7ff..18a3f78e 100644 --- a/internal/chain/manager.go +++ b/internal/chain/manager.go @@ -105,8 +105,8 @@ func (m *Manager) Synced() bool { func (m *Manager) BlockAtHeight(height uint64) (types.Block, bool) { sb, ok := m.cs.BlockAtHeight(stypes.BlockHeight(height)) var c types.Block - convertToCore(sb, &c) - return c, ok + convertToCore(sb, (*types.V1Block)(&c)) + return types.Block(c), ok } // IndexAtHeight return the chain index at the given height. @@ -131,7 +131,7 @@ func (m *Manager) TipState() consensus.State { // AcceptBlock adds b to the consensus set. func (m *Manager) AcceptBlock(b types.Block) error { var sb stypes.Block - convertToSiad(b, &sb) + convertToSiad(types.V1Block(b), &sb) return m.cs.AcceptBlock(sb) } diff --git a/internal/test/miner.go b/internal/test/miner.go index bd79419c..9406d14d 100644 --- a/internal/test/miner.go +++ b/internal/test/miner.go @@ -118,7 +118,7 @@ func (m *Miner) mineBlock(addr stypes.UnlockHash) error { } var b types.Block - convertToCore(&block, &b) + convertToCore(&block, (*types.V1Block)(&b)) if err := m.consensus.AcceptBlock(b); err != nil { return fmt.Errorf("failed to get block accepted: %w", err) } diff --git a/internal/test/renter.go b/internal/test/renter.go index 9a14b858..6be7d0fd 100644 --- a/internal/test/renter.go +++ b/internal/test/renter.go @@ -7,13 +7,12 @@ import ( "path/filepath" "time" - rhp2 "go.sia.tech/core/rhp/v2" + crhp2 "go.sia.tech/core/rhp/v2" "go.sia.tech/core/types" - irhp2 "go.sia.tech/hostd/internal/test/rhp/v2" + rhp2 "go.sia.tech/hostd/internal/test/rhp/v2" rhp3 "go.sia.tech/hostd/internal/test/rhp/v3" "go.sia.tech/hostd/persist/sqlite" "go.sia.tech/hostd/wallet" - "go.sia.tech/renterd/worker" "go.uber.org/zap" ) @@ -50,13 +49,13 @@ func (r *Renter) Wallet() *wallet.SingleAddressWallet { // NewRHP2Session creates a new session, locks a contract, and retrieves the // host's settings -func (r *Renter) NewRHP2Session(ctx context.Context, hostAddr string, hostKey types.PublicKey, contractID types.FileContractID) (*irhp2.RHP2Session, error) { +func (r *Renter) NewRHP2Session(ctx context.Context, hostAddr string, hostKey types.PublicKey, contractID types.FileContractID) (*rhp2.RHP2Session, error) { t, err := dialTransport(ctx, hostAddr, hostKey) if err != nil { return nil, err } - session := irhp2.NewRHP2Session(t, r.privKey, rhp2.ContractRevision{}, rhp2.HostSettings{}) + session := rhp2.NewRHP2Session(t, r.privKey, crhp2.ContractRevision{}, crhp2.HostSettings{}) ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() @@ -72,33 +71,33 @@ func (r *Renter) NewRHP3Session(ctx context.Context, hostAddr string, hostKey ty } // Settings returns the host's current settings -func (r *Renter) Settings(ctx context.Context, hostAddr string, hostKey types.PublicKey) (rhp2.HostSettings, error) { +func (r *Renter) Settings(ctx context.Context, hostAddr string, hostKey types.PublicKey) (crhp2.HostSettings, error) { t, err := dialTransport(ctx, hostAddr, hostKey) if err != nil { - return rhp2.HostSettings{}, fmt.Errorf("failed to create session: %w", err) + return crhp2.HostSettings{}, fmt.Errorf("failed to create session: %w", err) } defer t.Close() - settings, err := worker.RPCSettings(ctx, t) + settings, err := rhp2.RPCSettings(ctx, t) if err != nil { - return rhp2.HostSettings{}, fmt.Errorf("failed to get settings: %w", err) + return crhp2.HostSettings{}, fmt.Errorf("failed to get settings: %w", err) } return settings, nil } // FormContract forms a contract with the host -func (r *Renter) FormContract(ctx context.Context, hostAddr string, hostKey types.PublicKey, renterPayout, hostCollateral types.Currency, duration uint64) (rhp2.ContractRevision, error) { +func (r *Renter) FormContract(ctx context.Context, hostAddr string, hostKey types.PublicKey, renterPayout, hostCollateral types.Currency, duration uint64) (crhp2.ContractRevision, error) { t, err := dialTransport(ctx, hostAddr, hostKey) if err != nil { - return rhp2.ContractRevision{}, fmt.Errorf("failed to dial transport: %w", err) + return crhp2.ContractRevision{}, fmt.Errorf("failed to dial transport: %w", err) } defer t.Close() - settings, err := worker.RPCSettings(ctx, t) + settings, err := rhp2.RPCSettings(ctx, t) if err != nil { - return rhp2.ContractRevision{}, fmt.Errorf("failed to get host settings: %w", err) + return crhp2.ContractRevision{}, fmt.Errorf("failed to get host settings: %w", err) } cs := r.TipState() - contract := rhp2.PrepareContractFormation(r.privKey.PublicKey(), hostKey, renterPayout, hostCollateral, cs.Index.Height+duration, settings, r.WalletAddress()) - formationCost := rhp2.ContractFormationCost(cs, contract, settings.ContractPrice) + contract := crhp2.PrepareContractFormation(r.privKey.PublicKey(), hostKey, renterPayout, hostCollateral, cs.Index.Height+duration, settings, r.WalletAddress()) + formationCost := crhp2.ContractFormationCost(cs, contract, settings.ContractPrice) feeEstimate := r.TPool().RecommendedFee().Mul64(2000) formationTxn := types.Transaction{ MinerFees: []types.Currency{feeEstimate}, @@ -108,17 +107,17 @@ func (r *Renter) FormContract(ctx context.Context, hostAddr string, hostKey type toSign, release, err := r.wallet.FundTransaction(&formationTxn, fundAmount) if err != nil { - return rhp2.ContractRevision{}, fmt.Errorf("failed to fund transaction: %w", err) + return crhp2.ContractRevision{}, fmt.Errorf("failed to fund transaction: %w", err) } defer release() if err := r.wallet.SignTransaction(cs, &formationTxn, toSign, explicitCoveredFields(formationTxn)); err != nil { - return rhp2.ContractRevision{}, fmt.Errorf("failed to sign transaction: %w", err) + return crhp2.ContractRevision{}, fmt.Errorf("failed to sign transaction: %w", err) } - revision, _, err := worker.RPCFormContract(ctx, t, r.privKey, []types.Transaction{formationTxn}) + revision, _, err := rhp2.RPCFormContract(ctx, t, r.privKey, []types.Transaction{formationTxn}) if err != nil { - return rhp2.ContractRevision{}, fmt.Errorf("failed to form contract: %w", err) + return crhp2.ContractRevision{}, fmt.Errorf("failed to form contract: %w", err) } return revision, nil } @@ -135,7 +134,7 @@ func (r *Renter) PublicKey() types.PublicKey { // dialTransport is a convenience function that connects to the specified // host -func dialTransport(ctx context.Context, hostIP string, hostKey types.PublicKey) (_ *rhp2.Transport, err error) { +func dialTransport(ctx context.Context, hostIP string, hostKey types.PublicKey) (_ *crhp2.Transport, err error) { conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", hostIP) if err != nil { return nil, err @@ -155,7 +154,7 @@ func dialTransport(ctx context.Context, hostIP string, hostKey types.PublicKey) } }() - t, err := rhp2.NewRenterTransport(conn, hostKey) + t, err := crhp2.NewRenterTransport(conn, hostKey) if err != nil { conn.Close() return nil, err diff --git a/internal/test/rhp/v2/rhp.go b/internal/test/rhp/v2/rhp.go index 48a3f28b..54252cfc 100644 --- a/internal/test/rhp/v2/rhp.go +++ b/internal/test/rhp/v2/rhp.go @@ -13,10 +13,15 @@ import ( "sort" "time" - rhpv2 "go.sia.tech/core/rhp/v2" + rhp2 "go.sia.tech/core/rhp/v2" "go.sia.tech/core/types" ) +const ( + // minMessageSize is the minimum size of an RPC message + minMessageSize = 4096 +) + var ( errContractLocked = errors.New("contract is locked by another party") errContractFinalized = errors.New("contract cannot be revised further") @@ -25,18 +30,113 @@ var ( errInvalidMerkleProof = errors.New("host supplied invalid Merkle proof") ) +// RPCSettings calls the Settings RPC, returning the host's reported settings. +func RPCSettings(ctx context.Context, t *rhp2.Transport) (settings rhp2.HostSettings, err error) { + var resp rhp2.RPCSettingsResponse + if err := t.Call(rhp2.RPCSettingsID, nil, &resp); err != nil { + return rhp2.HostSettings{}, err + } else if err := json.Unmarshal(resp.Settings, &settings); err != nil { + return rhp2.HostSettings{}, fmt.Errorf("couldn't unmarshal json: %w", err) + } + + return settings, nil +} + +// RPCFormContract forms a contract with a host. +func RPCFormContract(ctx context.Context, t *rhp2.Transport, renterKey types.PrivateKey, txnSet []types.Transaction) (_ rhp2.ContractRevision, _ []types.Transaction, err error) { + // strip our signatures before sending + parents, txn := txnSet[:len(txnSet)-1], txnSet[len(txnSet)-1] + renterContractSignatures := txn.Signatures + txnSet[len(txnSet)-1].Signatures = nil + + // create request + renterPubkey := renterKey.PublicKey() + req := &rhp2.RPCFormContractRequest{ + Transactions: txnSet, + RenterKey: renterPubkey.UnlockKey(), + } + if err := t.WriteRequest(rhp2.RPCFormContractID, req); err != nil { + return rhp2.ContractRevision{}, nil, err + } + + // execute form contract RPC + var resp rhp2.RPCFormContractAdditions + if err := t.ReadResponse(&resp, 65536); err != nil { + return rhp2.ContractRevision{}, nil, err + } + + // merge host additions with txn + txn.SiacoinInputs = append(txn.SiacoinInputs, resp.Inputs...) + txn.SiacoinOutputs = append(txn.SiacoinOutputs, resp.Outputs...) + + // create initial (no-op) revision, transaction, and signature + fc := txn.FileContracts[0] + initRevision := types.FileContractRevision{ + ParentID: txn.FileContractID(0), + UnlockConditions: types.UnlockConditions{ + PublicKeys: []types.UnlockKey{ + renterPubkey.UnlockKey(), + t.HostKey().UnlockKey(), + }, + SignaturesRequired: 2, + }, + FileContract: types.FileContract{ + RevisionNumber: 1, + Filesize: fc.Filesize, + FileMerkleRoot: fc.FileMerkleRoot, + WindowStart: fc.WindowStart, + WindowEnd: fc.WindowEnd, + ValidProofOutputs: fc.ValidProofOutputs, + MissedProofOutputs: fc.MissedProofOutputs, + UnlockHash: fc.UnlockHash, + }, + } + revSig := renterKey.SignHash(hashRevision(initRevision)) + renterRevisionSig := types.TransactionSignature{ + ParentID: types.Hash256(initRevision.ParentID), + CoveredFields: types.CoveredFields{FileContractRevisions: []uint64{0}}, + PublicKeyIndex: 0, + Signature: revSig[:], + } + + // write our signatures + renterSigs := &rhp2.RPCFormContractSignatures{ + ContractSignatures: renterContractSignatures, + RevisionSignature: renterRevisionSig, + } + if err := t.WriteResponse(renterSigs); err != nil { + return rhp2.ContractRevision{}, nil, err + } + + // read the host's signatures and merge them with our own + var hostSigs rhp2.RPCFormContractSignatures + if err := t.ReadResponse(&hostSigs, minMessageSize); err != nil { + return rhp2.ContractRevision{}, nil, err + } + + txn.Signatures = append(renterContractSignatures, hostSigs.ContractSignatures...) + signedTxnSet := append(resp.Parents, append(parents, txn)...) + return rhp2.ContractRevision{ + Revision: initRevision, + Signatures: [2]types.TransactionSignature{ + renterRevisionSig, + hostSigs.RevisionSignature, + }, + }, signedTxnSet, nil +} + // RHP2Session represents a session with a host type RHP2Session struct { - transport *rhpv2.Transport - revision rhpv2.ContractRevision + transport *rhp2.Transport + revision rhp2.ContractRevision key types.PrivateKey appendRoots []types.Hash256 - settings rhpv2.HostSettings + settings rhp2.HostSettings lastSeen time.Time } // NewRHP2Session returns a new rhp2 session -func NewRHP2Session(t *rhpv2.Transport, key types.PrivateKey, rev rhpv2.ContractRevision, settings rhpv2.HostSettings) *RHP2Session { +func NewRHP2Session(t *rhp2.Transport, key types.PrivateKey, rev rhp2.ContractRevision, settings rhp2.HostSettings) *RHP2Session { return &RHP2Session{ transport: t, key: key, @@ -46,9 +146,9 @@ func NewRHP2Session(t *rhpv2.Transport, key types.PrivateKey, rev rhpv2.Contract } // Append appends the sector to the contract -func (s *RHP2Session) Append(ctx context.Context, sector *[rhpv2.SectorSize]byte, price, collateral types.Currency) (types.Hash256, error) { - err := s.Write(ctx, []rhpv2.RPCWriteAction{{ - Type: rhpv2.RPCWriteActionAppend, +func (s *RHP2Session) Append(ctx context.Context, sector *[rhp2.SectorSize]byte, price, collateral types.Currency) (types.Hash256, error) { + err := s.Write(ctx, []rhp2.RPCWriteAction{{ + Type: rhp2.RPCWriteActionAppend, Data: sector[:], }}, price, collateral) if err != nil { @@ -75,13 +175,13 @@ func (s *RHP2Session) Delete(ctx context.Context, sectorIndices []uint64, price // iterate backwards from the end of the contract, swapping each "good" // sector with one of the "bad" sectors. - var actions []rhpv2.RPCWriteAction + var actions []rhp2.RPCWriteAction cIndex := s.revision.NumSectors() - 1 for _, rIndex := range sectorIndices { if cIndex != rIndex { // swap a "good" sector for a "bad" sector - actions = append(actions, rhpv2.RPCWriteAction{ - Type: rhpv2.RPCWriteActionSwap, + actions = append(actions, rhp2.RPCWriteAction{ + Type: rhp2.RPCWriteActionSwap, A: uint64(cIndex), B: uint64(rIndex), }) @@ -89,8 +189,8 @@ func (s *RHP2Session) Delete(ctx context.Context, sectorIndices []uint64, price cIndex-- } // trim all "bad" sectors - actions = append(actions, rhpv2.RPCWriteAction{ - Type: rhpv2.RPCWriteActionTrim, + actions = append(actions, rhp2.RPCWriteAction{ + Type: rhp2.RPCWriteActionTrim, A: uint64(len(sectorIndices)), }) @@ -106,7 +206,7 @@ func (s *RHP2Session) Delete(ctx context.Context, sectorIndices []uint64, price func (s *RHP2Session) HostKey() types.PublicKey { return s.revision.HostKey() } // Read reads the given sections -func (s *RHP2Session) Read(ctx context.Context, w io.Writer, sections []rhpv2.RPCReadRequestSection, price types.Currency) (err error) { +func (s *RHP2Session) Read(ctx context.Context, w io.Writer, sections []rhp2.RPCReadRequestSection, price types.Currency) (err error) { empty := true for _, s := range sections { empty = empty && s.Length == 0 @@ -129,7 +229,7 @@ func (s *RHP2Session) Read(ctx context.Context, w io.Writer, sections []rhpv2.RP renterSig := s.key.SignHash(revisionHash) // construct the request - req := &rhpv2.RPCReadRequest{ + req := &rhp2.RPCReadRequest{ Sections: sections, MerkleProof: true, @@ -140,13 +240,13 @@ func (s *RHP2Session) Read(ctx context.Context, w io.Writer, sections []rhpv2.RP } var hostSig *types.Signature - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { - if err := transport.WriteRequest(rhpv2.RPCReadID, req); err != nil { + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { + if err := transport.WriteRequest(rhp2.RPCReadID, req); err != nil { return err } // ensure we send RPCLoopReadStop before returning - defer transport.WriteResponse(&rhpv2.RPCReadStop) + defer transport.WriteResponse(&rhp2.RPCReadStop) // read all sections for _, sec := range sections { @@ -163,7 +263,7 @@ func (s *RHP2Session) Read(ctx context.Context, w io.Writer, sections []rhpv2.RP // yet, they should send an empty ReadResponse containing just the // signature. if hostSig == nil { - var resp rhpv2.RPCReadResponse + var resp rhp2.RPCReadResponse if err := transport.ReadResponse(&resp, 4096); err != nil { return wrapResponseErr(err, "couldn't read signature", "host rejected Read request") } @@ -193,7 +293,7 @@ func (s *RHP2Session) Reconnect(ctx context.Context, hostIP string, hostKey type if err != nil { return err } - s.transport, err = rhpv2.NewRenterTransport(conn, hostKey) + s.transport, err = rhp2.NewRenterTransport(conn, hostKey) if err != nil { return err } @@ -247,7 +347,7 @@ func (s *RHP2Session) Refresh(ctx context.Context, sessionTTL time.Duration, ren } // RenewContract renews the contract -func (s *RHP2Session) RenewContract(ctx context.Context, txnSet []types.Transaction, finalPayment types.Currency) (_ rhpv2.ContractRevision, _ []types.Transaction, err error) { +func (s *RHP2Session) RenewContract(ctx context.Context, txnSet []types.Transaction, finalPayment types.Currency) (_ rhp2.ContractRevision, _ []types.Transaction, err error) { // strip our signatures before sending parents, txn := txnSet[:len(txnSet)-1], txnSet[len(txnSet)-1] renterContractSignatures := txn.Signatures @@ -262,7 +362,7 @@ func (s *RHP2Session) RenewContract(ctx context.Context, txnSet []types.Transact finalOldRevision.RevisionNumber = math.MaxUint64 // construct the renew request - req := &rhpv2.RPCRenewAndClearContractRequest{ + req := &rhp2.RPCRenewAndClearContractRequest{ Transactions: txnSet, RenterKey: s.revision.Revision.UnlockConditions.PublicKeys[0], FinalValidProofValues: newValid, @@ -270,14 +370,14 @@ func (s *RHP2Session) RenewContract(ctx context.Context, txnSet []types.Transact } // send the request - var resp rhpv2.RPCFormContractAdditions - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { - if err := transport.WriteRequest(rhpv2.RPCRenewClearContractID, req); err != nil { + var resp rhp2.RPCFormContractAdditions + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { + if err := transport.WriteRequest(rhp2.RPCRenewClearContractID, req); err != nil { return err } return transport.ReadResponse(&resp, 65536) }); err != nil { - return rhpv2.ContractRevision{}, nil, err + return rhp2.ContractRevision{}, nil, err } // merge host additions with txn @@ -310,34 +410,34 @@ func (s *RHP2Session) RenewContract(ctx context.Context, txnSet []types.Transact // create signatures finalRevSig := s.key.SignHash(hashRevision(finalOldRevision)) - renterSigs := &rhpv2.RPCRenewAndClearContractSignatures{ + renterSigs := &rhp2.RPCRenewAndClearContractSignatures{ ContractSignatures: renterContractSignatures, RevisionSignature: renterRevisionSig, FinalRevisionSignature: finalRevSig, } // send the signatures and read the host's signatures - var hostSigs rhpv2.RPCRenewAndClearContractSignatures - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { + var hostSigs rhp2.RPCRenewAndClearContractSignatures + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { if err := transport.WriteResponse(renterSigs); err != nil { return err } return transport.ReadResponse(&hostSigs, 4096) }); err != nil { - return rhpv2.ContractRevision{}, nil, err + return rhp2.ContractRevision{}, nil, err } // merge host signatures with our own txn.Signatures = append(renterContractSignatures, hostSigs.ContractSignatures...) signedTxnSet := append(resp.Parents, append(parents, txn)...) - return rhpv2.ContractRevision{ + return rhp2.ContractRevision{ Revision: initRevision, Signatures: [2]types.TransactionSignature{renterRevisionSig, hostSigs.RevisionSignature}, }, signedTxnSet, nil } // Revision returns the contract revision -func (s *RHP2Session) Revision() (rev rhpv2.ContractRevision) { +func (s *RHP2Session) Revision() (rev rhp2.ContractRevision) { b, _ := json.Marshal(s.revision) // deep copy if err := json.Unmarshal(b, &rev); err != nil { panic(err) // should never happen @@ -345,6 +445,18 @@ func (s *RHP2Session) Revision() (rev rhpv2.ContractRevision) { return rev } +// RPCAppendCost returns the cost of a single append +func (s *RHP2Session) RPCAppendCost(remainingDuration uint64) (types.Currency, types.Currency, error) { + var sector [rhp2.SectorSize]byte + actions := []rhp2.RPCWriteAction{{Type: rhp2.RPCWriteActionAppend, Data: sector[:]}} + cost, err := s.settings.RPCWriteCost(actions, 0, remainingDuration, true) + if err != nil { + return types.ZeroCurrency, types.ZeroCurrency, err + } + price, collateral := cost.Total() + return price, collateral, nil +} + // SectorRoots returns n roots at offset. func (s *RHP2Session) SectorRoots(ctx context.Context, offset, n uint64, price types.Currency) (roots []types.Hash256, err error) { if !s.isRevisable() { @@ -363,7 +475,7 @@ func (s *RHP2Session) SectorRoots(ctx context.Context, offset, n uint64, price t newValid, newMissed := updateRevisionOutputs(&rev, price, types.ZeroCurrency) revisionHash := hashRevision(rev) - req := &rhpv2.RPCSectorRootsRequest{ + req := &rhp2.RPCSectorRootsRequest{ RootOffset: uint64(offset), NumRoots: uint64(n), @@ -374,13 +486,13 @@ func (s *RHP2Session) SectorRoots(ctx context.Context, offset, n uint64, price t } // execute the sector roots RPC - var resp rhpv2.RPCSectorRootsResponse - if err = s.withTransport(ctx, func(t *rhpv2.Transport) error { - if err := t.WriteRequest(rhpv2.RPCSectorRootsID, req); err != nil { + var resp rhp2.RPCSectorRootsResponse + if err = s.withTransport(ctx, func(t *rhp2.Transport) error { + if err := t.WriteRequest(rhp2.RPCSectorRootsID, req); err != nil { return err } else if err := t.ReadResponse(&resp, uint64(4096+32*n)); err != nil { - readCtx := fmt.Sprintf("couldn't read %v response", rhpv2.RPCSectorRootsID) - rejectCtx := fmt.Sprintf("host rejected %v request", rhpv2.RPCSectorRootsID) + readCtx := fmt.Sprintf("couldn't read %v response", rhp2.RPCSectorRootsID) + rejectCtx := fmt.Sprintf("host rejected %v request", rhp2.RPCSectorRootsID) return wrapResponseErr(err, readCtx, rejectCtx) } else { return nil @@ -398,17 +510,17 @@ func (s *RHP2Session) SectorRoots(ctx context.Context, offset, n uint64, price t s.revision.Signatures[1].Signature = resp.Signature[:] // verify the proof - if !rhpv2.VerifySectorRangeProof(resp.MerkleProof, resp.SectorRoots, offset, offset+n, s.revision.NumSectors(), rev.FileMerkleRoot) { + if !rhp2.VerifySectorRangeProof(resp.MerkleProof, resp.SectorRoots, offset, offset+n, s.revision.NumSectors(), rev.FileMerkleRoot) { return nil, errInvalidMerkleProof } return resp.SectorRoots, nil } // Settings returns the host settings -func (s *RHP2Session) Settings() *rhpv2.HostSettings { return &s.settings } +func (s *RHP2Session) Settings() *rhp2.HostSettings { return &s.settings } // Write performs the given write actions -func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, price, collateral types.Currency) (err error) { +func (s *RHP2Session) Write(ctx context.Context, actions []rhp2.RPCWriteAction, price, collateral types.Currency) (err error) { if !s.isRevisable() { return errContractFinalized } else if len(actions) == 0 { @@ -423,10 +535,10 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, newFilesize := rev.Filesize for _, action := range actions { switch action.Type { - case rhpv2.RPCWriteActionAppend: - newFilesize += rhpv2.SectorSize - case rhpv2.RPCWriteActionTrim: - newFilesize -= rhpv2.SectorSize * action.A + case rhp2.RPCWriteActionAppend: + newFilesize += rhp2.SectorSize + case rhp2.RPCWriteActionTrim: + newFilesize -= rhp2.SectorSize * action.A } } @@ -438,8 +550,8 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, go func() { s.appendRoots = s.appendRoots[:0] for _, action := range actions { - if action.Type == rhpv2.RPCWriteActionAppend { - s.appendRoots = append(s.appendRoots, rhpv2.SectorRoot((*[rhpv2.SectorSize]byte)(action.Data))) + if action.Type == rhp2.RPCWriteActionAppend { + s.appendRoots = append(s.appendRoots, rhp2.SectorRoot((*[rhp2.SectorSize]byte)(action.Data))) } } close(precompChan) @@ -448,7 +560,7 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, defer func() { <-precompChan }() // create request - req := &rhpv2.RPCWriteRequest{ + req := &rhp2.RPCWriteRequest{ Actions: actions, MerkleProof: true, @@ -458,9 +570,9 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, } // send request and read merkle proof - var merkleResp rhpv2.RPCWriteMerkleProof - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { - if err := transport.WriteRequest(rhpv2.RPCWriteID, req); err != nil { + var merkleResp rhp2.RPCWriteMerkleProof + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { + if err := transport.WriteRequest(rhp2.RPCWriteID, req); err != nil { return err } else if err := transport.ReadResponse(&merkleResp, 4096); err != nil { return wrapResponseErr(err, "couldn't read Merkle proof response", "host rejected Write request") @@ -476,9 +588,9 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, leafHashes := merkleResp.OldLeafHashes oldRoot, newRoot := types.Hash256(rev.FileMerkleRoot), merkleResp.NewMerkleRoot <-precompChan - if newFilesize > 0 && !rhpv2.VerifyDiffProof(actions, s.revision.NumSectors(), proofHashes, leafHashes, oldRoot, newRoot, s.appendRoots) { + if newFilesize > 0 && !rhp2.VerifyDiffProof(actions, s.revision.NumSectors(), proofHashes, leafHashes, oldRoot, newRoot, s.appendRoots) { err := errInvalidMerkleProof - s.withTransport(ctx, func(transport *rhpv2.Transport) error { return transport.WriteResponseErr(err) }) + s.withTransport(ctx, func(transport *rhp2.Transport) error { return transport.WriteResponseErr(err) }) return err } @@ -487,13 +599,13 @@ func (s *RHP2Session) Write(ctx context.Context, actions []rhpv2.RPCWriteAction, rev.Filesize = newFilesize copy(rev.FileMerkleRoot[:], newRoot[:]) revisionHash := hashRevision(rev) - renterSig := &rhpv2.RPCWriteResponse{ + renterSig := &rhp2.RPCWriteResponse{ Signature: s.key.SignHash(revisionHash), } // exchange signatures - var hostSig rhpv2.RPCWriteResponse - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { + var hostSig rhp2.RPCWriteResponse + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { if err := transport.WriteResponse(renterSig); err != nil { return fmt.Errorf("couldn't write signature response: %w", err) } else if err := transport.ReadResponse(&hostSig, 4096); err != nil { @@ -527,16 +639,16 @@ func (s *RHP2Session) isRevisable() bool { } func (s *RHP2Session) lock(ctx context.Context, id types.FileContractID, key types.PrivateKey, timeout time.Duration) (err error) { - req := &rhpv2.RPCLockRequest{ + req := &rhp2.RPCLockRequest{ ContractID: id, Signature: s.transport.SignChallenge(key), Timeout: uint64(timeout.Milliseconds()), } // execute lock RPC - var resp rhpv2.RPCLockResponse - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { - if err := transport.Call(rhpv2.RPCLockID, req, &resp); err != nil { + var resp rhp2.RPCLockResponse + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { + if err := transport.Call(rhp2.RPCLockID, req, &resp); err != nil { return err } transport.SetChallenge(resp.NewChallenge) @@ -561,14 +673,14 @@ func (s *RHP2Session) lock(ctx context.Context, id types.FileContractID, key typ } else if resp.Revision.RevisionNumber == math.MaxUint64 { return errContractFinalized } - s.revision = rhpv2.ContractRevision{ + s.revision = rhp2.ContractRevision{ Revision: resp.Revision, Signatures: [2]types.TransactionSignature{resp.Signatures[0], resp.Signatures[1]}, } return nil } -func (s *RHP2Session) readSection(w io.Writer, t *rhpv2.Transport, sec rhpv2.RPCReadRequestSection) (hostSig *types.Signature, _ error) { +func (s *RHP2Session) readSection(w io.Writer, t *rhp2.Transport, sec rhp2.RPCReadRequestSection) (hostSig *types.Signature, _ error) { // NOTE: normally, we would call ReadResponse here to read an AEAD RPC // message, verify the tag and decrypt, and then pass the data to // VerifyProof. As an optimization, we instead stream the message @@ -596,9 +708,9 @@ func (s *RHP2Session) readSection(w io.Writer, t *rhpv2.Transport, sec rhpv2.RPC } else if binary.LittleEndian.Uint64(lenbuf) != uint64(sec.Length) { return nil, errors.New("host sent wrong amount of sector data") } - proofStart := sec.Offset / rhpv2.LeafSize - proofEnd := proofStart + sec.Length/rhpv2.LeafSize - rpv := rhpv2.NewRangeProofVerifier(proofStart, proofEnd) + proofStart := sec.Offset / rhp2.LeafSize + proofEnd := proofStart + sec.Length/rhp2.LeafSize + rpv := rhp2.NewRangeProofVerifier(proofStart, proofEnd) tee := io.TeeReader(io.LimitReader(msgReader, int64(sec.Length)), &segWriter{w: w}) // the proof verifier Reads one segment at a time, so bufio is crucial // for performance here @@ -609,7 +721,7 @@ func (s *RHP2Session) readSection(w io.Writer, t *rhpv2.Transport, sec rhpv2.RPC if _, err := io.ReadFull(msgReader, lenbuf); err != nil { return nil, fmt.Errorf("couldn't read proof len: %w", err) } - if binary.LittleEndian.Uint64(lenbuf) != uint64(rhpv2.RangeProofSize(rhpv2.LeavesPerSector, proofStart, proofEnd)) { + if binary.LittleEndian.Uint64(lenbuf) != uint64(rhp2.RangeProofSize(rhp2.LeavesPerSector, proofStart, proofEnd)) { return nil, errors.New("invalid proof size") } proof := make([]types.Hash256, binary.LittleEndian.Uint64(lenbuf)) @@ -637,9 +749,9 @@ func (s *RHP2Session) sufficientCollateral(collateral types.Currency) bool { } func (s *RHP2Session) updateSettings(ctx context.Context) (err error) { - var resp rhpv2.RPCSettingsResponse - if err := s.withTransport(ctx, func(transport *rhpv2.Transport) error { - return transport.Call(rhpv2.RPCSettingsID, nil, &resp) + var resp rhp2.RPCSettingsResponse + if err := s.withTransport(ctx, func(transport *rhp2.Transport) error { + return transport.Call(rhp2.RPCSettingsID, nil, &resp) }); err != nil { return err } @@ -651,15 +763,15 @@ func (s *RHP2Session) updateSettings(ctx context.Context) (err error) { } func (s *RHP2Session) unlock(ctx context.Context) (err error) { - s.revision = rhpv2.ContractRevision{} + s.revision = rhp2.ContractRevision{} s.key = nil - return s.withTransport(ctx, func(transport *rhpv2.Transport) error { - return transport.WriteRequest(rhpv2.RPCUnlockID, nil) + return s.withTransport(ctx, func(transport *rhp2.Transport) error { + return transport.WriteRequest(rhp2.RPCUnlockID, nil) }) } -func (s *RHP2Session) withTransport(ctx context.Context, fn func(t *rhpv2.Transport) error) (err error) { +func (s *RHP2Session) withTransport(ctx context.Context, fn func(t *rhp2.Transport) error) (err error) { errChan := make(chan error) go func() { defer close(errChan) @@ -707,7 +819,7 @@ func updateRevisionOutputs(rev *types.FileContractRevision, cost, collateral typ } func wrapResponseErr(err error, readCtx, rejectCtx string) error { - if errors.As(err, new(*rhpv2.RPCError)) { + if errors.As(err, new(*rhp2.RPCError)) { return fmt.Errorf("%s: %w", rejectCtx, err) } if err != nil { @@ -718,7 +830,7 @@ func wrapResponseErr(err error, readCtx, rejectCtx string) error { type segWriter struct { w io.Writer - buf [rhpv2.LeafSize * 64]byte + buf [rhp2.LeafSize * 64]byte len int } @@ -728,7 +840,7 @@ func (sw *segWriter) Write(p []byte) (int, error) { n := copy(sw.buf[sw.len:], p) sw.len += n p = p[n:] - segs := sw.buf[:sw.len-(sw.len%rhpv2.LeafSize)] + segs := sw.buf[:sw.len-(sw.len%rhp2.LeafSize)] if _, err := sw.w.Write(segs); err != nil { return 0, err } diff --git a/rhp/v2/contracts.go b/rhp/v2/contracts.go index 4b236828..bd6e7a4a 100644 --- a/rhp/v2/contracts.go +++ b/rhp/v2/contracts.go @@ -6,41 +6,8 @@ import ( rhp2 "go.sia.tech/core/rhp/v2" "go.sia.tech/core/types" - "go.sia.tech/hostd/host/contracts" ) -type rpcCost struct { - Base types.Currency - Storage types.Currency - Ingress types.Currency - Egress types.Currency - Collateral types.Currency -} - -func (c rpcCost) Add(o rpcCost) rpcCost { - return rpcCost{ - Base: c.Base.Add(o.Base), - Storage: c.Storage.Add(o.Storage), - Ingress: c.Ingress.Add(o.Ingress), - Egress: c.Egress.Add(o.Egress), - Collateral: c.Collateral.Add(o.Collateral), - } -} - -func (c rpcCost) Total() (cost, collateral types.Currency) { - return c.Base.Add(c.Storage).Add(c.Ingress).Add(c.Egress), c.Collateral -} - -func (c rpcCost) ToUsage() contracts.Usage { - return contracts.Usage{ - RPCRevenue: c.Base, - StorageRevenue: c.Storage, - EgressRevenue: c.Egress, - IngressRevenue: c.Ingress, - RiskedCollateral: c.Collateral, - } -} - var ( // ErrNoContractLocked is returned when a contract revision is attempted // without a contract being locked. @@ -54,119 +21,8 @@ var ( // ErrContractExpired is returned when a contract revision is attempted // after the contract has expired. ErrContractExpired = errors.New("contract has expired") - - // ErrInvalidSectorLength is returned when a sector is not the correct - // length. - ErrInvalidSectorLength = errors.New("length of sector data must be exactly 4MiB") - - // ErrTrimOutOfBounds is returned when a trim operation exceeds the total - // number of sectors - ErrTrimOutOfBounds = errors.New("trim size exceeds number of sectors") - // ErrSwapOutOfBounds is returned when one of the swap indices exceeds the - // total number of sectors - ErrSwapOutOfBounds = errors.New("swap index is out of bounds") - // ErrUpdateOutOfBounds is returned when the update index exceeds the total - // number of sectors - ErrUpdateOutOfBounds = errors.New("update index is out of bounds") - // ErrOffsetOutOfBounds is returned when the offset exceeds and length - // exceed the sector size. - ErrOffsetOutOfBounds = errors.New("update section is out of bounds") - // ErrUpdateProofSize is returned when a proof is requested for an update - // operation that is not a multiple of 64 bytes. - ErrUpdateProofSize = errors.New("update section is not a multiple of the segment size") ) -// validateWriteActions validates the actions received by the renter for the -// write RPC and estimates the cost of completing the actions. -func validateWriteActions(actions []rhp2.RPCWriteAction, oldSectors uint64, proof bool, remainingDuration uint64, settings rhp2.HostSettings) (rpcCost, error) { - var uploadBytes uint64 - newSectors := oldSectors - for _, action := range actions { - switch action.Type { - case rhp2.RPCWriteActionAppend: - if len(action.Data) != rhp2.SectorSize { - return rpcCost{}, fmt.Errorf("invalid sector size: %v: %w", len(action.Data), ErrInvalidSectorLength) - } - newSectors++ - uploadBytes += rhp2.SectorSize - case rhp2.RPCWriteActionTrim: - if action.A > newSectors { - return rpcCost{}, ErrTrimOutOfBounds - } - newSectors -= action.A - case rhp2.RPCWriteActionSwap: - if action.A >= newSectors || action.B >= newSectors { - return rpcCost{}, ErrSwapOutOfBounds - } - case rhp2.RPCWriteActionUpdate: - idx, offset := action.A, action.B - if idx >= newSectors { - return rpcCost{}, ErrUpdateOutOfBounds - } else if offset+uint64(len(action.Data)) > rhp2.SectorSize { - return rpcCost{}, ErrOffsetOutOfBounds - } else if proof && (offset%rhp2.LeafSize != 0) || len(action.Data)%rhp2.LeafSize != 0 { - return rpcCost{}, ErrUpdateProofSize - } - default: - return rpcCost{}, fmt.Errorf("unknown write action type '%v'", action.Type) - } - } - - cost := rpcCost{ - Base: settings.BaseRPCPrice, // base cost of the RPC - Ingress: settings.UploadBandwidthPrice.Mul64(uploadBytes), // cost of uploading the new sectors - } - - if newSectors > oldSectors { - additionalSectors := (newSectors - oldSectors) - cost.Storage = settings.StoragePrice.Mul64(rhp2.SectorSize * additionalSectors * remainingDuration) // cost of storing the new sectors - cost.Collateral = settings.Collateral.Mul64(rhp2.SectorSize * additionalSectors * remainingDuration) // collateral for the new sectors - } - - if proof { - // estimate cost of Merkle proof - proofSize := 32 * (128 + len(actions)) - cost.Egress = settings.DownloadBandwidthPrice.Mul64(uint64(proofSize)) - } - return cost, nil -} - -func validateReadActions(sections []rhp2.RPCReadRequestSection, proof bool, settings rhp2.HostSettings) (rpcCost, error) { - // validate the request sections and calculate the cost - var bandwidth uint64 - for _, sec := range sections { - switch { - case uint64(sec.Offset)+uint64(sec.Length) > rhp2.SectorSize: - return rpcCost{}, ErrOffsetOutOfBounds - case sec.Length == 0: - return rpcCost{}, errors.New("length cannot be zero") - case proof && (sec.Offset%rhp2.LeafSize != 0 || sec.Length%rhp2.LeafSize != 0): - return rpcCost{}, errors.New("offset and length must be multiples of SegmentSize when requesting a Merkle proof") - } - - bandwidth += uint64(sec.Length) - if proof { - start := sec.Offset / rhp2.LeafSize - end := (sec.Offset + sec.Length) / rhp2.LeafSize - proofSize := rhp2.RangeProofSize(rhp2.LeavesPerSector, start, end) - bandwidth += proofSize * 32 - } - } - - return rpcCost{ - Base: settings.BaseRPCPrice.Add(settings.SectorAccessPrice.Mul64(uint64(len(sections)))), - Egress: settings.DownloadBandwidthPrice.Mul64(bandwidth), - }, nil -} - -func rpcSectorRootsCost(count, offset uint64, settings rhp2.HostSettings) rpcCost { - proofSize := rhp2.RangeProofSize(rhp2.LeavesPerSector, offset, offset+count) - return rpcCost{ - Base: settings.BaseRPCPrice, - Egress: settings.DownloadBandwidthPrice.Mul64((count + proofSize) * 32), - } -} - func contractUnlockConditions(hostKey, renterKey types.UnlockKey) types.UnlockConditions { return types.UnlockConditions{ PublicKeys: []types.UnlockKey{renterKey, hostKey}, diff --git a/rhp/v2/rpc.go b/rhp/v2/rpc.go index 346ddcc0..20619055 100644 --- a/rhp/v2/rpc.go +++ b/rhp/v2/rpc.go @@ -435,7 +435,7 @@ func (sh *SessionHandler) rpcSectorRoots(s *session, log *zap.Logger) (contracts return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) } - costs := rpcSectorRootsCost(req.NumRoots, req.RootOffset, settings) + costs := settings.RPCSectorRootsCost(req.NumRoots, req.RootOffset) cost, _ := costs.Total() // revise the contract @@ -497,7 +497,7 @@ func (sh *SessionHandler) rpcSectorRoots(s *session, log *zap.Logger) (contracts costs.Egress = costs.Egress.Add(excess) } - usage := costs.ToUsage() + usage := newUsageFromRPCCost(costs) if err := updater.Commit(signedRevision, usage); err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to commit contract revision: %w", err) @@ -534,7 +534,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage remainingDuration := uint64(s.contract.Revision.WindowEnd) - currentHeight // validate the requested actions oldSectors := s.contract.Revision.Filesize / rhp2.SectorSize - costs, err := validateWriteActions(req.Actions, oldSectors, req.MerkleProof, remainingDuration, settings) + costs, err := settings.RPCWriteCost(req.Actions, oldSectors, remainingDuration, req.MerkleProof) if err != nil { err := fmt.Errorf("failed to validate write actions: %w", err) s.t.WriteResponseErr(err) @@ -690,7 +690,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage costs.Collateral = risked // commit the contract modifications - usage := costs.ToUsage() + usage := newUsageFromRPCCost(costs) if err := contractUpdater.Commit(signedRevision, usage); err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to commit contract modifications: %w", err) @@ -726,7 +726,7 @@ func (sh *SessionHandler) rpcRead(s *session, log *zap.Logger) (contracts.Usage, } // validate the request sections and calculate the cost - costs, err := validateReadActions(req.Sections, req.MerkleProof, settings) + costs, err := settings.RPCReadCost(req.Sections, req.MerkleProof) if err != nil { s.t.WriteResponseErr(err) return contracts.Usage{}, fmt.Errorf("failed to validate read request: %w", err) @@ -776,8 +776,8 @@ func (sh *SessionHandler) rpcRead(s *session, log *zap.Logger) (contracts.Usage, if !underflow { costs.Egress = costs.Egress.Add(excess) } - usage := costs.ToUsage() // commit the contract revision + usage := newUsageFromRPCCost(costs) if err := updater.Commit(signedRevision, usage); err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to commit contract revision: %w", err) @@ -839,6 +839,17 @@ func (sh *SessionHandler) rpcRead(s *session, log *zap.Logger) (contracts.Usage, return usage, <-stopSignal } +// newUsageFromRPCCost returns a new Usage from the given RPCCost. +func newUsageFromRPCCost(c rhp2.RPCCost) contracts.Usage { + return contracts.Usage{ + RPCRevenue: c.Base, + StorageRevenue: c.Storage, + EgressRevenue: c.Egress, + IngressRevenue: c.Ingress, + RiskedCollateral: c.Collateral, + } +} + func convertToPublicKey(uc types.UnlockKey) (types.PublicKey, error) { if uc.Algorithm != types.SpecifierEd25519 { return types.PublicKey{}, errors.New("unsupported signature algorithm") diff --git a/rhp/v2/rpc_test.go b/rhp/v2/rpc_test.go index 0ff9b428..b4f81111 100644 --- a/rhp/v2/rpc_test.go +++ b/rhp/v2/rpc_test.go @@ -74,7 +74,11 @@ func TestUploadDownload(t *testing.T) { } // upload the sector remainingDuration = contractExpiration - currentHeight - price, collateral := rhp2.RPCAppendCost(*session.Settings(), remainingDuration) + price, collateral, err := session.RPCAppendCost(remainingDuration) + if err != nil { + t.Fatal(err) + } + writtenRoot, err := session.Append(context.Background(), §or, price, collateral) if err != nil { t.Fatal(err) @@ -83,7 +87,7 @@ func TestUploadDownload(t *testing.T) { } // check the host's sector roots matches the sector we just uploaded - price = rhp2.RPCSectorRootsCost(*session.Settings(), 1) + price, _ = session.Settings().RPCSectorRootsCost(0, 1).Total() roots, err := session.SectorRoots(context.Background(), 0, 1, price) if err != nil { t.Fatal(err) @@ -108,7 +112,12 @@ func TestUploadDownload(t *testing.T) { }, } - price = rhp2.RPCReadCost(*session.Settings(), sections) + // calculate the price + cost, err := session.Settings().RPCReadCost(sections, true) + if err != nil { + t.Fatal(err) + } + price, _ = cost.Total() var buf bytes.Buffer ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) @@ -155,7 +164,7 @@ func TestRenew(t *testing.T) { settings := *session.Settings() current := session.Revision().Revision additionalCollateral := rhp2.ContractRenewalCollateral(current.FileContract, 1<<22, settings, renter.TipState().Index.Height, renewHeight) - renewed, basePrice := rhp2.PrepareContractRenewal(current, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, host.PublicKey(), settings, renewHeight) + renewed, basePrice := rhp2.PrepareContractRenewal(current, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, settings, renewHeight) renewalTxn := types.Transaction{ FileContracts: []types.FileContract{renewed}, } @@ -241,7 +250,10 @@ func TestRenew(t *testing.T) { } // upload the sector remainingDuration = contractExpiration - currentHeight - _, collateral := rhp2.RPCAppendCost(*session.Settings(), remainingDuration) + _, collateral, err := session.RPCAppendCost(remainingDuration) + if err != nil { + t.Fatal(err) + } // overpay for the sector, leaving a few hastings for the renewal remainingValue := types.NewCurrency64(25) price := origin.Revision.ValidRenterPayout().Sub(remainingValue) @@ -262,7 +274,7 @@ func TestRenew(t *testing.T) { renewHeight := origin.Revision.WindowEnd + 10 current := session.Revision().Revision additionalCollateral := rhp2.ContractRenewalCollateral(current.FileContract, 1<<22, settings, renter.TipState().Index.Height, renewHeight) - renewed, basePrice := rhp2.PrepareContractRenewal(session.Revision().Revision, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, host.PublicKey(), settings, renewHeight) + renewed, basePrice := rhp2.PrepareContractRenewal(session.Revision().Revision, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, settings, renewHeight) renewalTxn := types.Transaction{ FileContracts: []types.FileContract{renewed}, } @@ -355,7 +367,10 @@ func TestRenew(t *testing.T) { } // upload the sector remainingDuration = contractExpiration - currentHeight - price, collateral := rhp2.RPCAppendCost(*session.Settings(), remainingDuration) + price, collateral, err := session.RPCAppendCost(remainingDuration) + if err != nil { + t.Fatal(err) + } writtenRoot, err := session.Append(context.Background(), §or, price, collateral) if err != nil { t.Fatal(err) @@ -373,7 +388,7 @@ func TestRenew(t *testing.T) { renewHeight := origin.Revision.WindowEnd + 10 current := session.Revision().Revision additionalCollateral := rhp2.ContractRenewalCollateral(current.FileContract, 1<<22, settings, renter.TipState().Index.Height, renewHeight) - renewed, basePrice := rhp2.PrepareContractRenewal(session.Revision().Revision, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, host.PublicKey(), settings, renewHeight) + renewed, basePrice := rhp2.PrepareContractRenewal(session.Revision().Revision, renter.WalletAddress(), types.Siacoins(10), additionalCollateral, settings, renewHeight) renewalTxn := types.Transaction{ FileContracts: []types.FileContract{renewed}, } @@ -455,7 +470,10 @@ func BenchmarkUpload(b *testing.B) { } // calculate the cost of uploading a sector remainingDuration = contractExpiration - currentHeight - price, collateral := rhp2.RPCAppendCost(*session.Settings(), remainingDuration) + price, collateral, err := session.RPCAppendCost(remainingDuration) + if err != nil { + b.Fatal(err) + } // generate b.N sectors sectors := make([][rhp2.SectorSize]byte, b.N) @@ -525,7 +543,11 @@ func BenchmarkDownload(b *testing.B) { frand.Read(sector[:256]) // upload the sector - price, collateral := rhp2.RPCAppendCost(*session.Settings(), remainingDuration) + session.Settings().RPCWriteCost([]rhp2.RPCWriteAction{{Type: rhp2.RPCWriteActionAppend}}, uint64(b.N), remainingDuration, true) + price, collateral, err := session.RPCAppendCost(remainingDuration) + if err != nil { + b.Fatal(err) + } root, err := session.Append(context.Background(), §or, price, collateral) if err != nil { b.Fatal(err) @@ -544,7 +566,12 @@ func BenchmarkDownload(b *testing.B) { Offset: 0, Length: rhp2.SectorSize, }} - price := rhp2.RPCReadCost(*session.Settings(), sections) + + cost, err := session.Settings().RPCReadCost(sections, true) + if err != nil { + b.Fatal(err) + } + price, _ := cost.Total() if err := session.Read(context.Background(), io.Discard, sections, price); err != nil { b.Fatal(err) } diff --git a/wallet/wallet.go b/wallet/wallet.go index e97f960f..1b675018 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -193,7 +193,7 @@ func (sw *SingleAddressWallet) Address() types.Address { // UnlockConditions returns the unlock conditions of the wallet. func (sw *SingleAddressWallet) UnlockConditions() types.UnlockConditions { - return sw.priv.PublicKey().StandardUnlockConditions() + return types.StandardUnlockConditions(sw.priv.PublicKey()) } // Balance returns the balance of the wallet. @@ -292,7 +292,7 @@ func (sw *SingleAddressWallet) FundTransaction(txn *types.Transaction, amount ty for i, sce := range fundingElements { txn.SiacoinInputs = append(txn.SiacoinInputs, types.SiacoinInput{ ParentID: types.SiacoinOutputID(sce.ID), - UnlockConditions: sw.priv.PublicKey().StandardUnlockConditions(), + UnlockConditions: types.StandardUnlockConditions(sw.priv.PublicKey()), }) toSign[i] = types.Hash256(sce.ID) sw.locked[sce.ID] = true @@ -471,13 +471,13 @@ func (sw *SingleAddressWallet) ProcessConsensusChange(cc modules.ConsensusChange blockHeight := uint64(cc.BlockHeight) - uint64(len(cc.AppliedBlocks)) + 1 for i := 0; i < len(cc.AppliedDiffs); i, blockHeight = i+1, blockHeight+1 { var block types.Block - convertToCore(cc.AppliedBlocks[i], &block) + convertToCore(cc.AppliedBlocks[i], (*types.V1Block)(&block)) + diff := cc.AppliedDiffs[i] index := types.ChainIndex{ ID: block.ID(), Height: blockHeight, } - // determine the source of each delayed output delayedOutputSources := make(map[types.SiacoinOutputID]TransactionSource) if blockHeight > uint64(stypes.MaturityDelay) { @@ -633,7 +633,8 @@ func (sw *SingleAddressWallet) ProcessConsensusChange(cc modules.ConsensusChange // apply transactions for i := 0; i < len(cc.AppliedBlocks); i, blockHeight = i+1, blockHeight+1 { var block types.Block - convertToCore(cc.AppliedBlocks[i], &block) + convertToCore(cc.AppliedBlocks[i], (*types.V1Block)(&block)) + index := types.ChainIndex{ ID: block.ID(), Height: blockHeight, @@ -759,7 +760,7 @@ func NewSingleAddressWallet(priv types.PrivateKey, cm ChainManager, tp Transacti log: log, tg: threadgroup.New(), - addr: priv.PublicKey().StandardAddress(), + addr: types.StandardUnlockHash(priv.PublicKey()), locked: make(map[types.SiacoinOutputID]bool), consensusLocked: make(map[types.SiacoinOutputID]bool),