diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index e9653bd73ece..8166b338be46 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -35,6 +35,7 @@ require ( cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -53,7 +54,7 @@ require ( github.com/getsentry/sentry-go v0.27.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect @@ -65,7 +66,6 @@ require ( github.com/linxGnu/grocksdb v1.9.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/gomega v1.28.1 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index ffa2e8b402ff..690a675f2e22 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -23,6 +23,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -107,8 +109,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 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= @@ -164,8 +166,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/server/v2/cometbft/go.mod b/server/v2/cometbft/go.mod index aa227ff3ffc6..e0a5cd741e1e 100644 --- a/server/v2/cometbft/go.mod +++ b/server/v2/cometbft/go.mod @@ -60,6 +60,7 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -132,7 +133,6 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect diff --git a/server/v2/cometbft/go.sum b/server/v2/cometbft/go.sum index de4a9135bc90..204943777173 100644 --- a/server/v2/cometbft/go.sum +++ b/server/v2/cometbft/go.sum @@ -58,6 +58,8 @@ github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/ github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -345,8 +347,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= diff --git a/server/v2/go.mod b/server/v2/go.mod index 2905d7e23c1c..5d2e67326fc3 100644 --- a/server/v2/go.mod +++ b/server/v2/go.mod @@ -47,6 +47,7 @@ require ( github.com/DataDog/zstd v1.5.5 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -67,7 +68,7 @@ require ( github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -83,7 +84,6 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/run v1.1.0 // indirect github.com/onsi/gomega v1.28.1 // indirect diff --git a/server/v2/go.sum b/server/v2/go.sum index e494b8b56be5..94c8173f7bd4 100644 --- a/server/v2/go.sum +++ b/server/v2/go.sum @@ -29,6 +29,8 @@ 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/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -146,8 +148,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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= @@ -227,8 +229,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 0304f938cfd2..dffbac74044b 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -78,6 +78,7 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -170,7 +171,6 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mdp/qrterminal/v3 v3.2.0 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 68882ebba027..1263e44742d7 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -256,6 +256,8 @@ github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/ github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -662,8 +664,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdp/qrterminal/v3 v3.2.0 h1:qteQMXO3oyTK4IHwj2mWsKYYRBOp1Pj2WRYFYYNTCdk= github.com/mdp/qrterminal/v3 v3.2.0/go.mod h1:XGGuua4Lefrl7TLEsSONiD+UEjQXJZ4mPzF+gWYIJkk= diff --git a/store/v2/commitment/iavl/tree_test.go b/store/v2/commitment/iavl/tree_test.go index 65503190b943..728347999a31 100644 --- a/store/v2/commitment/iavl/tree_test.go +++ b/store/v2/commitment/iavl/tree_test.go @@ -16,7 +16,12 @@ import ( func TestCommitterSuite(t *testing.T) { s := &commitment.CommitStoreTestSuite{ - NewStore: func(db corestore.KVStoreWithBatch, storeKeys, oldStoreKeys []string, logger corelog.Logger) (*commitment.CommitStore, error) { + NewStore: func( + db corestore.KVStoreWithBatch, + _ string, + storeKeys, oldStoreKeys []string, + logger corelog.Logger, + ) (*commitment.CommitStore, error) { multiTrees := make(map[string]commitment.Tree) cfg := DefaultConfig() mountTreeFn := func(storeKey string) (commitment.Tree, error) { diff --git a/store/v2/commitment/iavlv2/tree.go b/store/v2/commitment/iavlv2/tree.go new file mode 100644 index 000000000000..003c5f4f45e0 --- /dev/null +++ b/store/v2/commitment/iavlv2/tree.go @@ -0,0 +1,147 @@ +package iavlv2 + +import ( + "errors" + "fmt" + + corestore "cosmossdk.io/core/store" + "github.com/cosmos/iavl/v2" + ics23 "github.com/cosmos/ics23/go" + + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/commitment" +) + +var ( + _ commitment.Tree = (*Tree)(nil) + _ commitment.Reader = (*Tree)(nil) + _ store.PausablePruner = (*Tree)(nil) +) + +type Tree struct { + tree *iavl.Tree +} + +func NewTree(treeOptions iavl.TreeOptions, dbOptions iavl.SqliteDbOptions, pool *iavl.NodePool) (*Tree, error) { + sql, err := iavl.NewSqliteDb(pool, dbOptions) + if err != nil { + return nil, err + } + tree := iavl.NewTree(sql, pool, treeOptions) + return &Tree{tree: tree}, nil +} + +func (t *Tree) Set(key, value []byte) error { + _, err := t.tree.Set(key, value) + return err +} + +func (t *Tree) Remove(key []byte) error { + _, _, err := t.tree.Remove(key) + return err +} + +func (t *Tree) GetLatestVersion() (uint64, error) { + return uint64(t.tree.Version()), nil +} + +func (t *Tree) Hash() []byte { + return t.tree.Hash() +} + +func (t *Tree) Version() uint64 { + return uint64(t.tree.Version()) +} + +func (t *Tree) LoadVersion(version uint64) error { + if err := isHighBitSet(version); err != nil { + return err + } + + if version == 0 { + return nil + } + return t.tree.LoadVersion(int64(version)) +} + +func (t *Tree) Commit() ([]byte, uint64, error) { + h, v, err := t.tree.SaveVersion() + return h, uint64(v), err +} + +func (t *Tree) SetInitialVersion(version uint64) error { + if err := isHighBitSet(version); err != nil { + return err + } + t.tree.SetShouldCheckpoint() + return t.tree.SetInitialVersion(int64(version)) +} + +func (t *Tree) GetProof(version uint64, key []byte) (*ics23.CommitmentProof, error) { + if err := isHighBitSet(version); err != nil { + return nil, err + } + return t.tree.GetProof(int64(version), key) +} + +func (t *Tree) Get(version uint64, key []byte) ([]byte, error) { + if err := isHighBitSet(version); err != nil { + return nil, err + } + if int64(version) != t.tree.Version() { + cloned, err := t.tree.ReadonlyClone() + if err != nil { + return nil, err + } + if err = cloned.LoadVersion(int64(version)); err != nil { + return nil, err + } + return cloned.Get(key) + } else { + return t.tree.Get(key) + } +} + +func (t *Tree) Iterator(version uint64, start, end []byte, ascending bool) (corestore.Iterator, error) { + if err := isHighBitSet(version); err != nil { + return nil, err + } + if int64(version) != t.tree.Version() { + return nil, fmt.Errorf("loading past version not yet supported") + } + return t.tree.Iterator(start, end, ascending) +} + +func (t *Tree) Export(version uint64) (commitment.Exporter, error) { + return nil, errors.New("snapshot import/export not yet supported") +} + +func (t *Tree) Import(version uint64) (commitment.Importer, error) { + return nil, errors.New("snapshot import/export not yet supported") +} + +func (t *Tree) Close() error { + return t.tree.Close() +} + +func (t *Tree) Prune(version uint64) error { + if err := isHighBitSet(version); err != nil { + return err + } + + return t.tree.DeleteVersionsTo(int64(version)) +} + +// PausePruning is unnecessary in IAVL v2 due to the advanced pruning mechanism +func (t *Tree) PausePruning(bool) {} + +func (t *Tree) WorkingHash() []byte { + return t.tree.Hash() +} + +func isHighBitSet(version uint64) error { + if version&(1<<63) != 0 { + return fmt.Errorf("%d too large; uint64 with the highest bit set are not supported", version) + } + return nil +} diff --git a/store/v2/commitment/iavlv2/tree_test.go b/store/v2/commitment/iavlv2/tree_test.go new file mode 100644 index 000000000000..a173c453c976 --- /dev/null +++ b/store/v2/commitment/iavlv2/tree_test.go @@ -0,0 +1,46 @@ +package iavlv2 + +import ( + "fmt" + "testing" + + "github.com/cosmos/iavl/v2" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + corelog "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2/commitment" +) + +func TestCommitterSuite(t *testing.T) { + nodePool := iavl.NewNodePool() + s := &commitment.CommitStoreTestSuite{ + TreeType: "iavlv2", + NewStore: func( + db corestore.KVStoreWithBatch, + dbDir string, + storeKeys, oldStoreKeys []string, + logger corelog.Logger, + ) (*commitment.CommitStore, error) { + multiTrees := make(map[string]commitment.Tree) + mountTreeFn := func(storeKey string) (commitment.Tree, error) { + path := fmt.Sprintf("%s/%s", dbDir, storeKey) + tree, err := NewTree(iavl.DefaultTreeOptions(), iavl.SqliteDbOptions{Path: path}, nodePool) + require.NoError(t, err) + return tree, nil + } + for _, storeKey := range storeKeys { + multiTrees[storeKey], _ = mountTreeFn(storeKey) + } + oldTrees := make(map[string]commitment.Tree) + for _, storeKey := range oldStoreKeys { + oldTrees[storeKey], _ = mountTreeFn(storeKey) + } + + return commitment.NewCommitStore(multiTrees, oldTrees, db, logger) + }, + } + + suite.Run(t, s) +} diff --git a/store/v2/commitment/store_test_suite.go b/store/v2/commitment/store_test_suite.go index afb468de8595..c41a2540a070 100644 --- a/store/v2/commitment/store_test_suite.go +++ b/store/v2/commitment/store_test_suite.go @@ -28,12 +28,16 @@ const ( type CommitStoreTestSuite struct { suite.Suite - NewStore func(db corestore.KVStoreWithBatch, storeKeys, oldStoreKeys []string, logger corelog.Logger) (*CommitStore, error) + NewStore func(db corestore.KVStoreWithBatch, dbDir string, storeKeys, oldStoreKeys []string, logger corelog.Logger) (*CommitStore, error) + TreeType string } func (s *CommitStoreTestSuite) TestStore_Snapshotter() { + if s.TreeType == "iavlv2" { + s.T().Skip("FIXME: iavlv2 does not yet support snapshots") + } storeKeys := []string{storeKey1, storeKey2} - commitStore, err := s.NewStore(dbm.NewMemDB(), storeKeys, nil, coretesting.NewNopLogger()) + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) latestVersion := uint64(10) @@ -67,7 +71,7 @@ func (s *CommitStoreTestSuite) TestStore_Snapshotter() { }, } - targetStore, err := s.NewStore(dbm.NewMemDB(), storeKeys, nil, coretesting.NewNopLogger()) + targetStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) chunks := make(chan io.ReadCloser, kvCount*int(latestVersion)) @@ -130,7 +134,8 @@ func (s *CommitStoreTestSuite) TestStore_Snapshotter() { func (s *CommitStoreTestSuite) TestStore_LoadVersion() { storeKeys := []string{storeKey1, storeKey2} mdb := dbm.NewMemDB() - commitStore, err := s.NewStore(mdb, storeKeys, nil, coretesting.NewNopLogger()) + dbDir := s.T().TempDir() + commitStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) latestVersion := uint64(10) @@ -151,7 +156,7 @@ func (s *CommitStoreTestSuite) TestStore_LoadVersion() { } // load the store with the latest version - targetStore, err := s.NewStore(mdb, storeKeys, nil, coretesting.NewNopLogger()) + targetStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) err = targetStore.LoadVersion(latestVersion) s.Require().NoError(err) @@ -164,7 +169,7 @@ func (s *CommitStoreTestSuite) TestStore_LoadVersion() { // rollback to a previous version rollbackVersion := uint64(5) - rollbackStore, err := s.NewStore(mdb, storeKeys, nil, coretesting.NewNopLogger()) + rollbackStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) err = rollbackStore.LoadVersion(rollbackVersion) s.Require().NoError(err) @@ -185,7 +190,7 @@ func (s *CommitStoreTestSuite) TestStore_LoadVersion() { func (s *CommitStoreTestSuite) TestStore_Pruning() { storeKeys := []string{storeKey1, storeKey2} pruneOpts := store.NewPruningOptionWithCustom(10, 5) - commitStore, err := s.NewStore(dbm.NewMemDB(), storeKeys, nil, coretesting.NewNopLogger()) + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) latestVersion := uint64(100) @@ -225,7 +230,7 @@ func (s *CommitStoreTestSuite) TestStore_Pruning() { func (s *CommitStoreTestSuite) TestStore_GetProof() { storeKeys := []string{storeKey1, storeKey2} - commitStore, err := s.NewStore(dbm.NewMemDB(), storeKeys, nil, coretesting.NewNopLogger()) + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) toVersion := uint64(10) @@ -268,7 +273,7 @@ func (s *CommitStoreTestSuite) TestStore_GetProof() { func (s *CommitStoreTestSuite) TestStore_Get() { storeKeys := []string{storeKey1, storeKey2} - commitStore, err := s.NewStore(dbm.NewMemDB(), storeKeys, nil, coretesting.NewNopLogger()) + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) toVersion := uint64(10) @@ -303,7 +308,8 @@ func (s *CommitStoreTestSuite) TestStore_Get() { func (s *CommitStoreTestSuite) TestStore_Upgrades() { storeKeys := []string{storeKey1, storeKey2, storeKey3} commitDB := dbm.NewMemDB() - commitStore, err := s.NewStore(commitDB, storeKeys, nil, coretesting.NewNopLogger()) + commitDir := s.T().TempDir() + commitStore, err := s.NewStore(commitDB, commitDir, storeKeys, nil, coretesting.NewNopLogger()) s.Require().NoError(err) latestVersion := uint64(10) @@ -330,14 +336,14 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { } newStoreKeys := []string{storeKey1, storeKey2, storeKey3, "newStore1", "newStore2"} realStoreKeys := []string{storeKey1, storeKey2, "newStore1", "newStore2"} - oldStoreKeys := []string{storeKey1, storeKey3} - commitStore, err = s.NewStore(commitDB, newStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) + oldStoreKeys := []string{storeKey3} + commitStore, err = s.NewStore(commitDB, commitDir, newStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) s.Require().NoError(err) err = commitStore.LoadVersionAndUpgrade(latestVersion, upgrades) s.Require().NoError(err) // GetProof should work for the old stores - for _, storeKey := range []string{storeKey1, storeKey3} { + for _, storeKey := range []string{storeKey3} { for i := uint64(1); i <= latestVersion; i++ { for j := 0; j < kvCount; j++ { proof, err := commitStore.GetProof([]byte(storeKey), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) @@ -391,20 +397,20 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { // verify existing store for i := uint64(1); i < latestVersion*2; i++ { for j := 0; j < kvCount; j++ { - proof, err := commitStore.GetProof([]byte(storeKey2), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + prf, err := commitStore.GetProof([]byte(storeKey2), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) s.Require().NoError(err) - s.Require().NotNil(proof) + s.Require().NotNil(prf) } } // create a new commitment store with one more upgrades upgrades = &corestore.StoreUpgrades{ - Added: []string{storeKey3}, Deleted: []string{storeKey2}, + Added: []string{"newStore3"}, } - newRealStoreKeys := []string{storeKey1, storeKey3, "newStore1", "newStore2"} + newRealStoreKeys := []string{storeKey1, "newStore1", "newStore2", "newStore3"} oldStoreKeys = []string{storeKey2, storeKey3} - commitStore, err = s.NewStore(commitDB, newStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) + commitStore, err = s.NewStore(commitDB, commitDir, newRealStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) s.Require().NoError(err) err = commitStore.LoadVersionAndUpgrade(2*latestVersion-1, upgrades) s.Require().NoError(err) @@ -420,7 +426,8 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) } } - s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + err = commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs)) + s.Require().NoError(err) commitInfo, err := commitStore.Commit(i) s.Require().NoError(err) s.Require().NotNil(commitInfo) @@ -432,6 +439,7 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { // prune the old stores s.Require().NoError(commitStore.Prune(latestVersion)) + s.T().Logf("prune to version %d", latestVersion) // GetProof should fail for the old stores for _, storeKey := range []string{storeKey1, storeKey3} { for i := uint64(1); i <= latestVersion; i++ { @@ -441,6 +449,7 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { } } } + s.T().Log("GetProof should work for the new stores") // GetProof should not fail for the newly removed store for i := latestVersion + 1; i < latestVersion*2; i++ { for j := 0; j < kvCount; j++ { @@ -450,6 +459,7 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { } } + s.T().Logf("Prune to version %d", latestVersion*2) s.Require().NoError(commitStore.Prune(latestVersion * 2)) // GetProof should fail for the newly deleted stores for i := uint64(1); i < latestVersion*2; i++ { @@ -458,10 +468,11 @@ func (s *CommitStoreTestSuite) TestStore_Upgrades() { s.Require().Error(err) } } + s.T().Log("GetProof should work for the new added store") // GetProof should work for the new added store for i := latestVersion*2 + 1; i < latestVersion*3; i++ { for j := 0; j < kvCount; j++ { - proof, err := commitStore.GetProof([]byte(storeKey3), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + proof, err := commitStore.GetProof([]byte("newStore3"), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) s.Require().NoError(err) s.Require().NotNil(proof) } diff --git a/store/v2/go.mod b/store/v2/go.mod index 8c32d86dd0d7..a2351efc3b92 100644 --- a/store/v2/go.mod +++ b/store/v2/go.mod @@ -7,15 +7,16 @@ require ( cosmossdk.io/core/testing v0.0.0-20241108153815-606544c7be7e cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 cosmossdk.io/log v1.5.0 + github.com/bvinc/go-sqlite-lite v0.6.1 github.com/cockroachdb/pebble v1.1.0 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/iavl v1.3.1 + github.com/cosmos/iavl/v2 v2.0.0-20241128205019-1b18c0edbbd9 github.com/cosmos/ics23/go v0.11.0 - github.com/google/btree v1.1.2 + github.com/google/btree v1.1.3 github.com/hashicorp/go-metrics v0.5.3 github.com/linxGnu/grocksdb v1.9.3 - github.com/mattn/go-sqlite3 v1.14.22 github.com/spf13/cast v1.7.0 github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d @@ -26,6 +27,7 @@ require ( require ( cosmossdk.io/schema v0.3.0 // indirect github.com/DataDog/zstd v1.5.5 // indirect + github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect @@ -37,6 +39,7 @@ require ( github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/dot v1.6.2 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect @@ -48,6 +51,7 @@ require ( github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/kocubinski/costor-api v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -71,3 +75,5 @@ require ( google.golang.org/protobuf v1.35.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace cosmossdk.io/core => ../../core diff --git a/store/v2/go.sum b/store/v2/go.sum index 4a42918d7265..fa8b03c077ac 100644 --- a/store/v2/go.sum +++ b/store/v2/go.sum @@ -1,5 +1,3 @@ -cosmossdk.io/core v1.0.0-alpha.6 h1:5ukC4JcQKmemLQXcAgu/QoOvJI50hpBkIIg4ZT2EN8E= -cosmossdk.io/core v1.0.0-alpha.6/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY= cosmossdk.io/core/testing v0.0.0-20241108153815-606544c7be7e h1:F+ScucYxwrrDJU8guJXQXpGhdpziYSbxW6HMP2wCNxs= cosmossdk.io/core/testing v0.0.0-20241108153815-606544c7be7e/go.mod h1:3YvVv9aJayjPhdX0DY1IMrGse4sR63hNBWx2VtDWjGQ= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= @@ -15,10 +13,14 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e h1:dSeuFcs4WAJJnswS8vXy7YY1+fdlbVPuEVmDAfqvFOQ= +github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e/go.mod h1:uh71c5Vc3VNIplXOFXsnDy21T1BepgT32c5X/YPrOyc= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -55,6 +57,10 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fr github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.3.1 h1:+W1G2uSUtJMqMGpwz/fKiwZxY2DDT/9/0hyNLm6Geu0= github.com/cosmos/iavl v1.3.1/go.mod h1:T6SfBcyhulVIY2G/ZtAtQm/QiJvsuhIos52V4dWYk88= +github.com/cosmos/iavl-bench/bench v0.0.4 h1:J6zQPiBqF4CXMM3QBsLqZgQEBGY0taX85vLIZMhmAfQ= +github.com/cosmos/iavl-bench/bench v0.0.4/go.mod h1:j2rLae77EffacWcp7mmj3Uaa4AOAmZA7ymvhsuBQKKI= +github.com/cosmos/iavl/v2 v2.0.0-20241128205019-1b18c0edbbd9 h1:H+ttW6HTzezz2l3Fp/hFNNHWA+a+7qZgNDE5OFySTiY= +github.com/cosmos/iavl/v2 v2.0.0-20241128205019-1b18c0edbbd9/go.mod h1:7RSm0aeApe3S1x4TrLffvUL6pjOtMYV4glYnpAhr2lw= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -62,6 +68,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -102,8 +110,8 @@ 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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 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= @@ -127,6 +135,8 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -138,6 +148,8 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kocubinski/costor-api v1.1.1 h1:sgfJA7T/8IfZ59zxiMrED0xdjerAFuPNBTqyO90GiEE= +github.com/kocubinski/costor-api v1.1.1/go.mod h1:ESMBMDkKfN+9vvvhhNVdKLhbOmzI3O/i16iXvRM9Tuc= 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= @@ -155,8 +167,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -221,6 +231,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= diff --git a/store/v2/storage/sqlite/batch.go b/store/v2/storage/sqlite/batch.go index 783b597e04af..01252f2e0c7c 100644 --- a/store/v2/storage/sqlite/batch.go +++ b/store/v2/storage/sqlite/batch.go @@ -1,8 +1,11 @@ package sqlite import ( - "database/sql" + "errors" "fmt" + "sync" + + "github.com/bvinc/go-sqlite-lite/sqlite3" "cosmossdk.io/store/v2" ) @@ -23,24 +26,23 @@ type batchOp struct { } type Batch struct { - db *sql.DB - tx *sql.Tx + db *sqlite3.Conn + lock *sync.Mutex ops []batchOp size int - version uint64 + version int64 } -func NewBatch(db *sql.DB, version uint64) (*Batch, error) { - tx, err := db.Begin() - if err != nil { - return nil, fmt.Errorf("failed to create SQL transaction: %w", err) +func NewBatch(db *sqlite3.Conn, writeLock *sync.Mutex, version uint64) (*Batch, error) { + if isHighBitSet(version) { + return nil, fmt.Errorf("%d too large; uint64 with the highest bit set are not supported", version) } return &Batch{ db: db, - tx: tx, + lock: writeLock, ops: make([]batchOp, 0), - version: version, + version: int64(version), }, nil } @@ -53,12 +55,11 @@ func (b *Batch) Reset() error { b.ops = make([]batchOp, 0) b.size = 0 - tx, err := b.db.Begin() + err := b.db.Begin() if err != nil { return err } - b.tx = tx return nil } @@ -74,29 +75,37 @@ func (b *Batch) Delete(storeKey, key []byte) error { return nil } -func (b *Batch) Write() error { - _, err := b.tx.Exec(reservedUpsertStmt, reservedStoreKey, keyLatestHeight, b.version, 0, b.version) +func (b *Batch) Write() (err error) { + b.lock.Lock() + defer b.lock.Unlock() + err = b.db.Begin() if err != nil { + return fmt.Errorf("failed to start SQL transaction: %w", err) + } + defer func() { + if err != nil { + err = errors.Join(err, b.db.Rollback()) + } + }() + if err := b.db.Exec(reservedUpsertStmt, reservedStoreKey, keyLatestHeight, b.version, 0, b.version); err != nil { return fmt.Errorf("failed to exec SQL statement: %w", err) } for _, op := range b.ops { switch op.action { case batchActionSet: - _, err := b.tx.Exec(upsertStmt, op.storeKey, op.key, op.value, b.version, op.value) - if err != nil { + if err := b.db.Exec(upsertStmt, op.storeKey, op.key, op.value, b.version, op.value); err != nil { return fmt.Errorf("failed to exec SQL statement: %w", err) } case batchActionDel: - _, err := b.tx.Exec(delStmt, b.version, op.storeKey, op.key, b.version) - if err != nil { + if err := b.db.Exec(delStmt, b.version, op.storeKey, op.key, b.version); err != nil { return fmt.Errorf("failed to exec SQL statement: %w", err) } } } - if err := b.tx.Commit(); err != nil { + if err := b.db.Commit(); err != nil { return fmt.Errorf("failed to write SQL transaction: %w", err) } diff --git a/store/v2/storage/sqlite/db.go b/store/v2/storage/sqlite/db.go index 925648928601..6cd826757b01 100644 --- a/store/v2/storage/sqlite/db.go +++ b/store/v2/storage/sqlite/db.go @@ -2,13 +2,13 @@ package sqlite import ( "bytes" - "database/sql" "errors" "fmt" "path/filepath" "strings" + "sync" - _ "github.com/mattn/go-sqlite3" + "github.com/bvinc/go-sqlite-lite/sqlite3" corestore "cosmossdk.io/core/store" "cosmossdk.io/store/v2" @@ -18,7 +18,7 @@ import ( const ( driverName = "sqlite3" - dbName = "ss.db?cache=shared&mode=rwc&_journal_mode=WAL" + dbName = "ss.db" reservedStoreKey = "_RESERVED_" keyLatestHeight = "latest_height" keyPruneHeight = "prune_height" @@ -50,18 +50,24 @@ var ( ) type Database struct { - storage *sql.DB - + storage *sqlite3.Conn + connStr string + writeLock sync.Mutex // earliestVersion defines the earliest version set in the database, which is // only updated when the database is pruned. earliestVersion uint64 } func New(dataDir string) (*Database, error) { - storage, err := sql.Open(driverName, filepath.Join(dataDir, dbName)) + connStr := fmt.Sprintf("file:%s", filepath.Join(dataDir, dbName)) + db, err := sqlite3.Open(connStr) if err != nil { return nil, fmt.Errorf("failed to open sqlite DB: %w", err) } + err = db.Exec("PRAGMA journal_mode=WAL;") + if err != nil { + return nil, fmt.Errorf("failed to set journal mode: %w", err) + } stmt := ` CREATE TABLE IF NOT EXISTS state_storage ( @@ -76,18 +82,20 @@ func New(dataDir string) (*Database, error) { CREATE UNIQUE INDEX IF NOT EXISTS idx_store_key_version ON state_storage (store_key, key, version); ` - _, err = storage.Exec(stmt) + err = db.Exec(stmt) if err != nil { return nil, fmt.Errorf("failed to exec SQL statement: %w", err) } - pruneHeight, err := getPruneHeight(storage) + pruneHeight, err := getPruneHeight(db) if err != nil { return nil, fmt.Errorf("failed to get prune height: %w", err) } return &Database{ - storage: storage, + storage: db, + connStr: connStr, + writeLock: sync.Mutex{}, earliestVersion: pruneHeight, }, nil } @@ -99,10 +107,10 @@ func (db *Database) Close() error { } func (db *Database) NewBatch(version uint64) (store.Batch, error) { - return NewBatch(db.storage, version) + return NewBatch(db.storage, &db.writeLock, version) } -func (db *Database) GetLatestVersion() (uint64, error) { +func (db *Database) GetLatestVersion() (version uint64, err error) { stmt, err := db.storage.Prepare(` SELECT value FROM state_storage @@ -112,19 +120,32 @@ func (db *Database) GetLatestVersion() (uint64, error) { return 0, fmt.Errorf("failed to prepare SQL statement: %w", err) } - defer stmt.Close() - - var latestHeight uint64 - if err := stmt.QueryRow(reservedStoreKey, keyLatestHeight).Scan(&latestHeight); err != nil { - if errors.Is(err, sql.ErrNoRows) { - // in case of a fresh database - return 0, nil + defer func(stmt *sqlite3.Stmt) { + cErr := stmt.Close() + if cErr != nil { + err = errors.Join(err, fmt.Errorf("failed to close GetLatestVersion statement: %w", cErr)) } + }(stmt) - return 0, fmt.Errorf("failed to query row: %w", err) + err = stmt.Bind(reservedStoreKey, keyLatestHeight) + if err != nil { + return 0, fmt.Errorf("failed to bind GetLatestVersion statement: %w", err) } - - return latestHeight, nil + hasRow, err := stmt.Step() + if err != nil { + return 0, fmt.Errorf("failed to step through GetLatestVersion rows: %w", err) + } + if !hasRow { + // in case of a fresh database + return 0, nil + } + var v int64 + err = stmt.Scan(&v) + if err != nil { + return 0, fmt.Errorf("failed to scan GetLatestVersion row: %w", err) + } + version = uint64(v) + return version, nil } func (db *Database) VersionExists(v uint64) (bool, error) { @@ -137,7 +158,9 @@ func (db *Database) VersionExists(v uint64) (bool, error) { } func (db *Database) SetLatestVersion(version uint64) error { - _, err := db.storage.Exec(reservedUpsertStmt, reservedStoreKey, keyLatestHeight, version, 0, version) + db.writeLock.Lock() + defer db.writeLock.Unlock() + err := db.storage.Exec(reservedUpsertStmt, reservedStoreKey, keyLatestHeight, int64(version), 0, int64(version)) if err != nil { return fmt.Errorf("failed to exec SQL statement: %w", err) } @@ -172,19 +195,27 @@ func (db *Database) Get(storeKey []byte, targetVersion uint64, key []byte) ([]by var ( value []byte - tomb uint64 + tomb int64 ) - if err := stmt.QueryRow(storeKey, key, targetVersion).Scan(&value, &tomb); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } - - return nil, fmt.Errorf("failed to query row: %w", err) + err = stmt.Bind(storeKey, key, int64(targetVersion)) + if err != nil { + return nil, fmt.Errorf("failed to bind SQL statement: %w", err) + } + hasRow, err := stmt.Step() + if err != nil { + return nil, fmt.Errorf("failed to step through SQL rows: %w", err) + } + if !hasRow { + return nil, nil + } + err = stmt.Scan(&value, &tomb) + if err != nil { + return nil, fmt.Errorf("failed to scan row: %w", err) } // A tombstone of zero or a target version that is less than the tombstone // version means the key is not deleted at the target version. - if tomb == 0 || targetVersion < tomb { + if tomb == 0 || targetVersion < uint64(tomb) { return value, nil } @@ -198,14 +229,17 @@ func (db *Database) Get(storeKey []byte, targetVersion uint64, key []byte) ([]by // // We perform the prune by deleting all versions of a key, excluding reserved keys, // that are <= the given version, except for the latest version of the key. -func (db *Database) Prune(version uint64) error { - tx, err := db.storage.Begin() +func (db *Database) Prune(version uint64) (err error) { + v := int64(version) + db.writeLock.Lock() + defer db.writeLock.Unlock() + err = db.storage.Begin() if err != nil { return fmt.Errorf("failed to create SQL transaction: %w", err) } defer func() { if err != nil { - err = tx.Rollback() + err = errors.Join(err, db.storage.Rollback()) } }() @@ -218,8 +252,8 @@ func (db *Database) Prune(version uint64) error { t2.version <= ? ) AND store_key != ?; ` - if _, err := tx.Exec(pruneStmt, version, reservedStoreKey); err != nil { - return fmt.Errorf("failed to exec SQL statement: %w", err) + if err := db.storage.Exec(pruneStmt, v, reservedStoreKey); err != nil { + return fmt.Errorf("failed to exec prune keys statement: %w", err) } // prune removed stores @@ -235,22 +269,23 @@ func (db *Database) Prune(version uint64) error { WHERE s.store_key = t.key AND s.version <= t.max_version LIMIT 1 ); ` - if _, err := tx.Exec(pruneRemovedStoreKeysStmt, reservedStoreKey, valueRemovedStore, version, version); err != nil { - return fmt.Errorf("failed to exec SQL statement: %w", err) + if err := db.storage.Exec(pruneRemovedStoreKeysStmt, reservedStoreKey, valueRemovedStore, v); err != nil { + return fmt.Errorf("failed to exec prune store keys statement: %w", err) } // delete the removedKeys - if _, err := tx.Exec("DELETE FROM state_storage WHERE store_key = ? AND value = ? AND version <= ?", reservedStoreKey, valueRemovedStore, version); err != nil { - return fmt.Errorf("failed to exec SQL statement: %w", err) + if err := db.storage.Exec("DELETE FROM state_storage WHERE store_key = ? AND value = ? AND version <= ?", + reservedStoreKey, valueRemovedStore, v); err != nil { + return fmt.Errorf("failed to exec remove keys statement: %w", err) } // set the prune height so we can return for queries below this height - if _, err := tx.Exec(reservedUpsertStmt, reservedStoreKey, keyPruneHeight, version, 0, version); err != nil { - return fmt.Errorf("failed to exec SQL statement: %w", err) + if err := db.storage.Exec(reservedUpsertStmt, reservedStoreKey, keyPruneHeight, v, 0, v); err != nil { + return fmt.Errorf("failed to exec set prune height statement: %w", err) } - if err := tx.Commit(); err != nil { - return fmt.Errorf("failed to write SQL transaction: %w", err) + if err := db.storage.Commit(); err != nil { + return fmt.Errorf("failed to commit prune transaction: %w", err) } db.earliestVersion = version + 1 @@ -282,13 +317,15 @@ func (db *Database) ReverseIterator(storeKey []byte, version uint64, start, end } func (db *Database) PruneStoreKeys(storeKeys []string, version uint64) (err error) { - tx, err := db.storage.Begin() + db.writeLock.Lock() + defer db.writeLock.Unlock() + err = db.storage.Begin() if err != nil { return fmt.Errorf("failed to create SQL transaction: %w", err) } defer func() { if err != nil { - err = tx.Rollback() + err = errors.Join(err, db.storage.Rollback()) } }() @@ -296,12 +333,12 @@ func (db *Database) PruneStoreKeys(storeKeys []string, version uint64) (err erro flushRemovedStoreKeyStmt := `INSERT INTO state_storage(store_key, key, value, version) VALUES (?, ?, ?, ?)` for _, storeKey := range storeKeys { - if _, err := tx.Exec(flushRemovedStoreKeyStmt, reservedStoreKey, []byte(storeKey), valueRemovedStore, version); err != nil { + if err := db.storage.Exec(flushRemovedStoreKeyStmt, reservedStoreKey, []byte(storeKey), valueRemovedStore, version); err != nil { return fmt.Errorf("failed to exec SQL statement: %w", err) } } - return tx.Commit() + return db.storage.Commit() } func (db *Database) PrintRowsDebug() { @@ -312,49 +349,68 @@ func (db *Database) PrintRowsDebug() { defer stmt.Close() - rows, err := stmt.Query() + err = stmt.Exec() if err != nil { panic(fmt.Errorf("failed to execute SQL query: %w", err)) } var sb strings.Builder - for rows.Next() { + for { + hasRow, err := stmt.Step() + if err != nil { + panic(fmt.Errorf("failed to step through SQL rows: %w", err)) + } + if !hasRow { + break + } var ( storeKey []byte key []byte value []byte - version uint64 - tomb uint64 + version int64 + tomb int64 ) - if err := rows.Scan(&storeKey, &key, &value, &version, &tomb); err != nil { + if err := stmt.Scan(&storeKey, &key, &value, &version, &tomb); err != nil { panic(fmt.Sprintf("failed to scan row: %s", err)) } sb.WriteString(fmt.Sprintf("STORE_KEY: %s, KEY: %s, VALUE: %s, VERSION: %d, TOMBSTONE: %d\n", storeKey, key, value, version, tomb)) } - if err := rows.Err(); err != nil { - panic(fmt.Errorf("received unexpected error: %w", err)) - } fmt.Println(strings.TrimSpace(sb.String())) } -func getPruneHeight(storage *sql.DB) (uint64, error) { +func getPruneHeight(storage *sqlite3.Conn) (height uint64, err error) { stmt, err := storage.Prepare(`SELECT value FROM state_storage WHERE store_key = ? AND key = ?`) if err != nil { return 0, fmt.Errorf("failed to prepare SQL statement: %w", err) } - defer stmt.Close() - - var value uint64 - if err := stmt.QueryRow(reservedStoreKey, keyPruneHeight).Scan(&value); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return 0, nil + defer func(stmt *sqlite3.Stmt) { + cErr := stmt.Close() + if cErr != nil { + err = errors.Join(err, fmt.Errorf("failed to close SQL statement: %w", cErr)) } + }(stmt) - return 0, fmt.Errorf("failed to query row: %w", err) + if err = stmt.Bind(reservedStoreKey, keyPruneHeight); err != nil { + return 0, fmt.Errorf("failed to bind prune height SQL statement: %w", err) + } + hasRows, err := stmt.Step() + if err != nil { + return 0, fmt.Errorf("failed to step prune height SQL statement: %w", err) + } + if !hasRows { + return 0, nil } + var h int64 + if err = stmt.Scan(&h); err != nil { + return 0, fmt.Errorf("failed to scan prune height SQL statement: %w", err) + } + height = uint64(h) + return height, nil +} - return value, nil +func isHighBitSet(version uint64) bool { + return version&(1<<63) != 0 } diff --git a/store/v2/storage/sqlite/db_test.go b/store/v2/storage/sqlite/db_test.go index fc4c27e6bfd9..7ec950bf93a0 100644 --- a/store/v2/storage/sqlite/db_test.go +++ b/store/v2/storage/sqlite/db_test.go @@ -2,6 +2,7 @@ package sqlite import ( "fmt" + "math" "sync" "testing" @@ -88,7 +89,8 @@ func TestDatabase_ReverseIterator(t *testing.T) { } func TestParallelWrites(t *testing.T) { - db, err := New(t.TempDir()) + tmpDir := t.TempDir() + db, err := New(tmpDir) require.NoError(t, err) defer db.Close() @@ -198,3 +200,11 @@ func TestParallelWriteAndPruning(t *testing.T) { require.NoError(t, err) require.Equal(t, []byte(fmt.Sprintf("val-%d-%03d", version-1, 0)), val) } + +func TestUint64(t *testing.T) { + tmpDir := t.TempDir() + db, err := New(tmpDir) + require.NoError(t, err) + _, err = db.NewBatch(math.MaxUint64) + require.Error(t, err) +} diff --git a/store/v2/storage/sqlite/iterator.go b/store/v2/storage/sqlite/iterator.go index daf7e073db3c..dbe3339c0c25 100644 --- a/store/v2/storage/sqlite/iterator.go +++ b/store/v2/storage/sqlite/iterator.go @@ -7,22 +7,26 @@ import ( "slices" "strings" + "github.com/bvinc/go-sqlite-lite/sqlite3" + corestore "cosmossdk.io/core/store" ) var _ corestore.Iterator = (*iterator)(nil) type iterator struct { - statement *sql.Stmt - rows *sql.Rows + statement *sqlite3.Stmt key, val []byte start, end []byte valid bool err error } -func newIterator(db *Database, storeKey []byte, targetVersion uint64, start, end []byte, reverse bool) (*iterator, error) { - if targetVersion < db.earliestVersion { +func newIterator(db *Database, storeKey []byte, version uint64, start, end []byte, reverse bool) (*iterator, error) { + if isHighBitSet(version) { + return nil, fmt.Errorf("%d too large; uint64 with the highest bit set are not supported", version) + } + if version < db.earliestVersion { return &iterator{ start: start, end: end, @@ -31,8 +35,9 @@ func newIterator(db *Database, storeKey []byte, targetVersion uint64, start, end } var ( - keyClause = []string{"store_key = ?", "version <= ?"} - queryArgs []any + targetVersion = int64(version) + keyClause = []string{"store_key = ?", "version <= ?"} + queryArgs []any ) switch { @@ -72,18 +77,21 @@ func newIterator(db *Database, storeKey []byte, targetVersion uint64, start, end return nil, fmt.Errorf("failed to prepare SQL statement: %w", err) } - rows, err := stmt.Query(queryArgs...) + err = stmt.Bind(queryArgs...) if err != nil { _ = stmt.Close() - return nil, fmt.Errorf("failed to execute SQL query: %w", err) + return nil, fmt.Errorf("failed to bind SQL iterator query arguments: %w", err) } itr := &iterator{ statement: stmt, - rows: rows, start: start, end: end, - valid: rows.Next(), + } + itr.valid, err = itr.statement.Step() + if err != nil { + itr.err = fmt.Errorf("failed to step SQL iterator: %w", err) + return itr, nil } if !itr.valid { itr.err = fmt.Errorf("iterator invalid: %w", sql.ErrNoRows) @@ -106,7 +114,6 @@ func (itr *iterator) Close() (err error) { itr.valid = false itr.statement = nil - itr.rows = nil return err } @@ -128,8 +135,7 @@ func (itr *iterator) Value() []byte { } func (itr *iterator) Valid() bool { - if !itr.valid || itr.rows.Err() != nil { - itr.valid = false + if !itr.valid { return itr.valid } @@ -145,19 +151,16 @@ func (itr *iterator) Valid() bool { } func (itr *iterator) Next() { - if itr.rows.Next() { - itr.parseRow() + var hasRow bool + hasRow, itr.err = itr.statement.Step() + if itr.err != nil || !hasRow { + itr.valid = false return } - - itr.valid = false + itr.parseRow() } func (itr *iterator) Error() error { - if err := itr.rows.Err(); err != nil { - return err - } - return itr.err } @@ -166,7 +169,7 @@ func (itr *iterator) parseRow() { key []byte value []byte ) - if err := itr.rows.Scan(&key, &value); err != nil { + if err := itr.statement.Scan(&key, &value); err != nil { itr.err = fmt.Errorf("failed to scan row: %w", err) itr.valid = false return diff --git a/tests/go.mod b/tests/go.mod index d95f20fb91ac..1e417ff7635a 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -88,6 +88,7 @@ require ( github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect github.com/bytedance/sonic v1.12.4 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -175,7 +176,6 @@ require ( github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index 18f3a2b9b2de..94f80dca69bd 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -253,6 +253,8 @@ github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/ github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4= +github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -660,8 +662,6 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=