diff --git a/block/manager.go b/block/manager.go index d2804a5a6a..c64626ab84 100644 --- a/block/manager.go +++ b/block/manager.go @@ -62,6 +62,8 @@ type Manager struct { CommitInCh chan *types.Commit lastCommit atomic.Value + FraudProofCh chan *types.FraudProof + syncTarget uint64 blockInCh chan newBlockEvent syncCache map[uint64]*types.Block @@ -228,6 +230,22 @@ func (m *Manager) SyncLoop(ctx context.Context) { if err != nil { m.logger.Info("failed to sync next block", "error", err) } + case fraudProof := <-m.FraudProofCh: + m.logger.Debug("fraud proof received", "Block Height", "dummy block height") // TODO: Insert real block height + _ = fraudProof + // TODO(light-client): Set up a new cosmos-sdk app + // How to get expected appHash here? + + // success, err := m.executor.VerifyFraudProof(fraudProof, nil) + // if err != nil { + // m.logger.Error("failed to verify fraud proof", "error", err) + // continue + // } + // if success { + // // halt chain somehow + // defer context.WithCancel(ctx) + // } + case <-ctx.Done(): return } diff --git a/go.mod b/go.mod index f54d5fe310..65c9efbbc4 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/stretchr/testify v1.8.0 github.com/tendermint/tendermint v0.34.21 go.uber.org/multierr v1.8.0 - golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b - google.golang.org/grpc v1.48.0 + golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458 + google.golang.org/grpc v1.50.0 google.golang.org/protobuf v1.28.1 ) @@ -84,7 +84,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/klauspost/compress v1.15.9 // indirect - github.com/klauspost/cpuid/v2 v2.1.1 // indirect + github.com/klauspost/cpuid/v2 v2.1.0 // indirect github.com/koron/go-ssdp v0.0.3 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -158,14 +158,14 @@ require ( go.etcd.io/bbolt v1.3.6 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.10.0 // indirect - go.uber.org/zap v1.23.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect + go.uber.org/zap v1.22.0 // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect + golang.org/x/text v0.3.8 // indirect golang.org/x/tools v0.1.12 // indirect - google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect + google.golang.org/genproto v0.0.0-20221013201013-33fc6f83cba4 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -175,5 +175,6 @@ require ( replace ( github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.4 + github.com/tendermint/tendermint => github.com/celestiaorg/tendermint v0.34.22-0.20221013213714-8be9b54c8c21 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index 782932e2aa..d6403ee64b 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,8 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/celestiaorg/go-cnc v0.1.0 h1:u986OnTc7AtbUZ4reY+zRCiar4fDdR1KehyP78uwsXg= github.com/celestiaorg/go-cnc v0.1.0/go.mod h1:Zf03bWWq6aldv5cYEaWvJ+I+z34bT/exrS0tO0y/jN8= +github.com/celestiaorg/tendermint v0.34.22-0.20221013213714-8be9b54c8c21 h1:M1fprJ+U7Z3SZzDBeiuJ/vx21QgguOu+Ld9ALVDyLuY= +github.com/celestiaorg/tendermint v0.34.22-0.20221013213714-8be9b54c8c21/go.mod h1:zoyyiiihvTW8DnOr63YLxhYn/WK/QmE74CeIpS++hBE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -368,8 +370,8 @@ github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQan github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= -github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= +github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -697,8 +699,6 @@ github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKk github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/tendermint/tendermint v0.34.21 h1:UiGGnBFHVrZhoQVQ7EfwSOLuCtarqCSsRf8VrklqB7s= -github.com/tendermint/tendermint v0.34.21/go.mod h1:XDvfg6U7grcFTDx7VkzxnhazQ/bspGJAn4DZ6DcLLjQ= github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -746,8 +746,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= +go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -767,8 +767,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -855,8 +855,8 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458 h1:MgJ6t2zo8v0tbmLCueaCbF1RM+TtB0rs3Lv8DGtOIpY= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -956,8 +956,9 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -967,8 +968,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1105,8 +1107,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b h1:SfSkJugek6xm7lWywqth4r2iTrYLpD8lOj1nMIIhMNM= -google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20221013201013-33fc6f83cba4 h1:nZ28yoLJWNLTcERW43BN+JDsNQOdiZOFB9Dly/IUrjw= +google.golang.org/genproto v0.0.0-20221013201013-33fc6f83cba4/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/mocks/Application.go b/mocks/Application.go index 8467676da0..6a1354199a 100644 --- a/mocks/Application.go +++ b/mocks/Application.go @@ -68,6 +68,47 @@ func (_m *Application) Commit() types.ResponseCommit { return r0 } +// Commit provides a mock function with given fields: +func (_m *Application) GenerateFraudProof(_a0 types.RequestGenerateFraudProof) types.ResponseGenerateFraudProof { + ret := _m.Called(_a0) + + var r0 types.ResponseGenerateFraudProof + if rf, ok := ret.Get(0).(func(types.RequestGenerateFraudProof) types.ResponseGenerateFraudProof); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseGenerateFraudProof) + } + + return r0 +} + +func (_m *Application) VerifyFraudProof(_a0 types.RequestVerifyFraudProof) types.ResponseVerifyFraudProof { + ret := _m.Called(_a0) + + var r0 types.ResponseVerifyFraudProof + if rf, ok := ret.Get(0).(func(types.RequestVerifyFraudProof) types.ResponseVerifyFraudProof); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseVerifyFraudProof) + } + + return r0 +} + +// Commit provides a mock function with given fields: +func (_m *Application) GetAppHash(_a0 types.RequestGetAppHash) types.ResponseGetAppHash { + ret := _m.Called(_a0) + + var r0 types.ResponseGetAppHash + if rf, ok := ret.Get(0).(func(types.RequestGetAppHash) types.ResponseGetAppHash); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseGetAppHash) + } + + return r0 +} + // DeliverTx provides a mock function with given fields: _a0 func (_m *Application) DeliverTx(_a0 types.RequestDeliverTx) types.ResponseDeliverTx { ret := _m.Called(_a0) diff --git a/node/integration_test.go b/node/integration_test.go index 54ca673b32..1865045c77 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -41,6 +41,7 @@ func TestAggregatorMode(t *testing.T) { app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) key, _, _ := crypto.GenerateEd25519Key(rand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) @@ -92,7 +93,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { clientNodes := 4 aggCtx, aggCancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background()) - nodes, apps := createNodes(aggCtx, ctx, clientNodes+1, &wg, t) + nodes, apps := createNodes(aggCtx, ctx, clientNodes+1, false, &wg, t) wg.Add((clientNodes + 1) * clientNodes) for _, n := range nodes { @@ -162,12 +163,107 @@ func TestTxGossipingAndAggregation(t *testing.T) { require.NoError(err) nodeBlock, err := nodes[i].Store.LoadBlock(h) require.NoError(err) + // Only Intermediate state roots set by block aggregator are relevant, removed for sake of comparison + nodeBlock.Data.IntermediateStateRoots.RawRootsList = nil assert.Equal(aggBlock, nodeBlock) } } } -func createNodes(aggCtx, ctx context.Context, num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { +func TestFraudProofTrigger(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + var wg sync.WaitGroup + clientNodes := 4 + aggCtx, aggCancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(context.Background()) + nodes, apps := createNodes(aggCtx, ctx, clientNodes+1, true, &wg, t) + + wg.Add((clientNodes + 1) * clientNodes) + for _, n := range nodes { + require.NoError(n.Start()) + } + + // wait for nodes to start up and establish connections; 1 second ensures that test pass even on CI. + time.Sleep(1 * time.Second) + + for i := 1; i < len(nodes); i++ { + data := strconv.Itoa(i) + time.Now().String() + require.NoError(nodes[i].P2P.GossipTx(context.TODO(), []byte(data))) + } + + timeout := time.NewTimer(time.Second * 30) + doneChan := make(chan struct{}) + go func() { + defer close(doneChan) + wg.Wait() + }() + select { + case <-doneChan: + case <-timeout.C: + t.FailNow() + } + aggCancel() + time.Sleep(100 * time.Millisecond) + for _, n := range nodes { + require.NoError(n.Stop()) + } + cancel() + time.Sleep(100 * time.Millisecond) + aggApp := apps[0] + apps = apps[1:] + + aggApp.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + aggApp.AssertExpectations(t) + + for i, app := range apps { + app.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + app.AssertExpectations(t) + + // assert that we have most of the blocks from aggregator + beginCnt := 0 + endCnt := 0 + commitCnt := 0 + generateFraudProofCnt := 0 + for _, call := range app.Calls { + switch call.Method { + case "BeginBlock": + beginCnt++ + case "EndBlock": + endCnt++ + case "Commit": + commitCnt++ + case "GenerateFraudProof": + generateFraudProofCnt++ + } + } + aggregatorHeight := nodes[0].Store.Height() + adjustedHeight := int(aggregatorHeight - 3) // 3 is completely arbitrary + assert.GreaterOrEqual(beginCnt, adjustedHeight) + assert.GreaterOrEqual(endCnt, adjustedHeight) + assert.GreaterOrEqual(commitCnt, adjustedHeight) + + // GenerateFraudProof should have been called on each call to + // BeginBlock, DeliverTx, and EndBlock so the sum of their counts + // should be equal. + // Note: The value of clientNodes represents number of calls to DeliverTx + assert.Equal(beginCnt+clientNodes+endCnt, generateFraudProofCnt) + + // assert that all blocks known to node are same as produced by aggregator + for h := uint64(1); h <= nodes[i].Store.Height(); h++ { + nodeBlock, err := nodes[i].Store.LoadBlock(h) + require.NoError(err) + aggBlock, err := nodes[0].Store.LoadBlock(h) + require.NoError(err) + // Only Intermediate state roots set by block aggregator are relevant, removed for sake of comparison + nodeBlock.Data.IntermediateStateRoots.RawRootsList = nil + assert.Equal(aggBlock, nodeBlock) + } + } +} + +func createNodes(aggCtx, ctx context.Context, num int, isMalicious bool, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { t.Helper() if aggCtx == nil { @@ -188,16 +284,15 @@ func createNodes(aggCtx, ctx context.Context, num int, wg *sync.WaitGroup, t *te dalc := &mockda.DataAvailabilityLayerClient{} _ = dalc.Init([8]byte{}, nil, store.NewDefaultInMemoryKVStore(), log.TestingLogger()) _ = dalc.Start() - - nodes[0], apps[0] = createNode(aggCtx, 0, true, dalc, keys, wg, t) + nodes[0], apps[0] = createNode(aggCtx, 0, isMalicious, true, dalc, keys, wg, t) for i := 1; i < num; i++ { - nodes[i], apps[i] = createNode(ctx, i, false, dalc, keys, wg, t) + nodes[i], apps[i] = createNode(ctx, i, isMalicious, false, dalc, keys, wg, t) } return nodes, apps } -func createNode(ctx context.Context, n int, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { +func createNode(ctx context.Context, n int, isMalicious bool, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { t.Helper() require := require.New(t) // nodes will listen on consecutive ports on local interface @@ -227,6 +322,17 @@ func createNode(ctx context.Context, n int, aggregator bool, dalc da.DataAvailab app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + maliciousAppHash := []byte{9, 8, 7, 6} + nonMaliciousAppHash := []byte{1, 2, 3, 4} + if isMalicious && aggregator { + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: maliciousAppHash}) + } else { + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: nonMaliciousAppHash}) + } + + if isMalicious && !aggregator { + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{FraudProof: &abci.FraudProof{}}) + } app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}).Run(func(args mock.Arguments) { wg.Done() }) diff --git a/node/node.go b/node/node.go index 7de4ab8656..52f434042d 100644 --- a/node/node.go +++ b/node/node.go @@ -157,6 +157,7 @@ func NewNode( node.P2P.SetTxValidator(node.newTxValidator()) node.P2P.SetHeaderValidator(node.newHeaderValidator()) node.P2P.SetCommitValidator(node.newCommitValidator()) + node.P2P.SetFraudProofValidator(node.newFraudProofValidator()) return node, nil } @@ -349,6 +350,23 @@ func (n *Node) newCommitValidator() p2p.GossipValidator { } } +// newFraudProofValidator returns a pubsub validator that validates a fraud proof and forwards +// it to be verified +func (n *Node) newFraudProofValidator() p2p.GossipValidator { + return func(fraudProofMsg *p2p.GossipMessage) bool { + n.Logger.Debug("fraud proof received", "from", fraudProofMsg.From, "bytes", len(fraudProofMsg.Data)) + var fraudProof types.FraudProof + err := fraudProof.UnmarshalBinary(fraudProofMsg.Data) + if err != nil { + n.Logger.Error("failed to deserialize fraud proof", "error", err) + return false + } + // TODO(manav): Add validation checks for fraud proof here + n.blockManager.FraudProofCh <- &fraudProof + return true + } +} + func createAndStartIndexerService( conf config.NodeConfig, kvStore store.KVStore, diff --git a/p2p/client.go b/p2p/client.go index 970893dadd..17f8c43141 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -41,6 +41,8 @@ const ( // commitTopicSuffix is added after namespace to create pubsub topic for block commit gossiping. commitTopicSuffix = "-commit" + + fraudProofTopicSuffix = "-fraudProof" ) // Client is a P2P client, implemented with libp2p. @@ -63,6 +65,9 @@ type Client struct { headerGossiper *Gossiper headerValidator GossipValidator + fraudProofGossiper *Gossiper + fraudProofValidator GossipValidator + commitGossiper *Gossiper commitValidator GossipValidator @@ -144,6 +149,7 @@ func (c *Client) Close() error { return multierr.Combine( c.txGossiper.Close(), c.headerGossiper.Close(), + c.fraudProofGossiper.Close(), c.dht.Close(), c.host.Close(), ) @@ -182,6 +188,17 @@ func (c *Client) SetCommitValidator(validator GossipValidator) { c.commitValidator = validator } +// GossipHeader sends a fraud proof to the P2P network. +func (c *Client) GossipFraudProof(ctx context.Context, fraudProof []byte) error { + c.logger.Debug("Gossiping fraud proof", "len", len(fraudProof)) + return c.fraudProofGossiper.Publish(ctx, fraudProof) +} + +// SetFraudProofValidator sets the callback function, that will be invoked after a fraud proof is received from P2P network. +func (c *Client) SetFraudProofValidator(validator GossipValidator) { + c.fraudProofValidator = validator +} + // Addrs returns listen addresses of Client. func (c *Client) Addrs() []multiaddr.Multiaddr { return c.host.Addrs() @@ -345,6 +362,13 @@ func (c *Client) setupGossiping(ctx context.Context) error { } go c.commitGossiper.ProcessMessages(ctx) + c.fraudProofGossiper, err = NewGossiper(c.host, ps, c.getFraudProofTopic(), c.logger, + WithValidator(c.fraudProofValidator)) + if err != nil { + return err + } + go c.fraudProofGossiper.ProcessMessages(ctx) + return nil } @@ -389,3 +413,7 @@ func (c *Client) getHeaderTopic() string { func (c *Client) getCommitTopic() string { return c.getNamespace() + commitTopicSuffix } + +func (c *Client) getFraudProofTopic() string { + return c.getNamespace() + fraudProofTopicSuffix +} diff --git a/proto/get_deps.sh b/proto/get_deps.sh index 2a7d5a15c9..df307cfa45 100755 --- a/proto/get_deps.sh +++ b/proto/get_deps.sh @@ -2,8 +2,8 @@ cd "$(dirname "${BASH_SOURCE[0]}")" -TM_VERSION=v0.34.21 -TM_PROTO_URL=https://raw.githubusercontent.com/tendermint/tendermint/$TM_VERSION/proto/tendermint +TM_VERSION=abci_fraud_proofs +TM_PROTO_URL=https://raw.githubusercontent.com/celestiaorg/tendermint/$TM_VERSION/proto/tendermint TM_PROTO_FILES=( abci/types.proto diff --git a/proto/rollmint/rollmint.proto b/proto/rollmint/rollmint.proto index 0e3aec6496..c716d82530 100644 --- a/proto/rollmint/rollmint.proto +++ b/proto/rollmint/rollmint.proto @@ -79,3 +79,17 @@ message Block { Data data = 2; Commit last_commit = 3; } + +message FraudProof { + uint64 block_height = 1; + StateWitness state_witness = 2; +} + +message StateWitness { + repeated WitnessData witness_data = 1; +} + +message WitnessData { + bytes key = 1; + bytes value = 2; +} diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 340800f46b..367dfbfba1 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -36,6 +36,9 @@ message Request { RequestOfferSnapshot offer_snapshot = 13; RequestLoadSnapshotChunk load_snapshot_chunk = 14; RequestApplySnapshotChunk apply_snapshot_chunk = 15; + RequestGetAppHash get_app_hash = 16; + RequestGenerateFraudProof generate_fraud_proof = 17; + RequestVerifyFraudProof verify_fraud_proof = 18; } } @@ -124,6 +127,22 @@ message RequestApplySnapshotChunk { string sender = 3; } +// Gets the current appHash +message RequestGetAppHash {} + +// Generates a fraud proof +message RequestGenerateFraudProof { + RequestBeginBlock begin_block_request = 1 [(gogoproto.nullable) = false]; + repeated RequestDeliverTx deliver_tx_requests = 2; + RequestEndBlock end_block_request = 3; +} + +// Verifies a fraud proof +message RequestVerifyFraudProof { + FraudProof fraud_proof = 1; + bytes expected_app_hash = 2; +} + //---------------------------------------- // Response types @@ -145,6 +164,9 @@ message Response { ResponseOfferSnapshot offer_snapshot = 14; ResponseLoadSnapshotChunk load_snapshot_chunk = 15; ResponseApplySnapshotChunk apply_snapshot_chunk = 16; + ResponseGetAppHash get_app_hash = 17; + ResponseGenerateFraudProof generate_fraud_proof = 18; + ResponseVerifyFraudProof verify_fraud_proof = 19; } } @@ -282,6 +304,18 @@ message ResponseApplySnapshotChunk { } } +message ResponseGetAppHash { + bytes app_hash = 1; +} + +message ResponseGenerateFraudProof { + FraudProof fraud_proof = 1; +} + +message ResponseVerifyFraudProof { + bool success = 1; +} + //---------------------------------------- // Misc. @@ -389,6 +423,34 @@ message Snapshot { bytes metadata = 5; // Arbitrary application metadata } +// Represents a single-round fraudProof +message FraudProof { + int64 block_height = 1; + bytes app_hash = 2; + map state_witness = 3; + + RequestBeginBlock fraudulent_begin_block = 4; + RequestDeliverTx fraudulent_deliver_tx = 5; + RequestEndBlock fraudulent_end_block = 6; +} + +// State witness with a list of all witness data +message StateWitness { + // store level proof + tendermint.crypto.ProofOp proof = 1; + // substore level hash + bytes root_hash = 2; + // List of witness data + repeated WitnessData witness_data = 3; +} + +// Witness data containing a key/value pair and a Merkle proof for said key/value pair +message WitnessData { + bytes key = 1; + bytes value = 2; + tendermint.crypto.ProofOp proof = 3; +} + //---------------------------------------- // Service Definition @@ -410,4 +472,7 @@ service ABCIApplication { returns (ResponseLoadSnapshotChunk); rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); + rpc GetAppHash(RequestGetAppHash) returns (ResponseGetAppHash); + rpc GenerateFraudProof(RequestGenerateFraudProof) returns (ResponseGenerateFraudProof); + rpc VerifyFraudProof(RequestVerifyFraudProof) returns (ResponseVerifyFraudProof); } diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index 37c26f4331..fcb1dea9f1 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -420,6 +420,8 @@ func TestTx(t *testing.T) { mockApp.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) mockApp.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) mockApp.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) + mockApp.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + mockApp.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) err = rpc.node.Start() require.NoError(err) @@ -630,6 +632,8 @@ func TestValidatorSetHandling(t *testing.T) { app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) key, _, _ := crypto.GenerateEd25519Key(crand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(crand.Reader) diff --git a/rpc/json/service_test.go b/rpc/json/service_test.go index eb8fcda3b9..2be2a3bf94 100644 --- a/rpc/json/service_test.go +++ b/rpc/json/service_test.go @@ -277,6 +277,8 @@ func getRPC(t *testing.T) (*mocks.Application, *client.Client) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{ GasWanted: 1000, GasUsed: 1000, diff --git a/state/executor.go b/state/executor.go index 1ccdd0c0ee..ea10c6902b 100644 --- a/state/executor.go +++ b/state/executor.go @@ -21,6 +21,8 @@ import ( "github.com/celestiaorg/rollmint/types" ) +var fraudProofsEnabled = true + // BlockExecutor creates and applies blocks and maintains state. type BlockExecutor struct { proposerAddress []byte @@ -174,6 +176,20 @@ func (e *BlockExecutor) Commit(ctx context.Context, state types.State, block *ty return appHash, retainHeight, nil } +func (e *BlockExecutor) VerifyFraudProof(fraudProof abci.FraudProof, expectedAppHash []byte) (bool, error) { + resp, err := e.proxyApp.VerifyFraudProofSync( + abci.RequestVerifyFraudProof{ + FraudProof: &fraudProof, + ExpectedAppHash: expectedAppHash, + }, + ) + if err != nil { + return false, err + } + return resp.Success, nil + +} + func (e *BlockExecutor) updateState(state types.State, block *types.Block, abciResponses *tmstate.ABCIResponses, validatorUpdates []*tmtypes.Validator) (types.State, error) { nValSet := state.NextValidators.Copy() lastHeightValSetChanged := state.LastHeightValidatorsChanged @@ -274,7 +290,20 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t validTxs := 0 invalidTxs := 0 - var err error + currentIsrs := block.Data.IntermediateStateRoots.RawRootsList + currentIsrIndex := 0 + + if fraudProofsEnabled { + if currentIsrs != nil { + expectedLength := len(block.Data.Txs) + 2 + // BeginBlock + DeliverTxs + EndBlock + if len(currentIsrs) != expectedLength { + return nil, fmt.Errorf("invalid length of ISR list: %d, expected length: %d", len(currentIsrs), expectedLength) + } + } + } + + ISRs := make([][]byte, 0) e.proxyApp.SetResponseCallback(func(req *abci.Request, res *abci.Response) { if r, ok := res.Value.(*abci.Response_DeliverTx); ok { @@ -290,6 +319,28 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t } }) + genAndGossipFraudProofIfNeeded := func(beginBlockRequest *abci.RequestBeginBlock, deliverTxRequests []*abci.RequestDeliverTx, endBlockRequest *abci.RequestEndBlock) (err error) { + if fraudProofsEnabled { + isr, err := e.getAppHash() + if err != nil { + return err + } + ISRs = append(ISRs, isr) + isFraud := e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + if isFraud { + fraudProof, err := e.generateFraudProof(beginBlockRequest, deliverTxRequests, endBlockRequest) + if err != nil { + return err + } + // TODO: gossip fraudProof to P2P network + // fraudTx: current DeliverTx + _ = fraudProof + } + currentIsrIndex++ + } + return nil + } + hash := block.Hash() abciHeader, err := abciconv.ToABCIHeaderPB(&block.Header) if err != nil { @@ -297,35 +348,91 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t } abciHeader.ChainID = e.chainID abciHeader.ValidatorsHash = state.Validators.Hash() - abciResponses.BeginBlock, err = e.proxyApp.BeginBlockSync( - abci.RequestBeginBlock{ - Hash: hash[:], - Header: abciHeader, - LastCommitInfo: abci.LastCommitInfo{ - Round: 0, - Votes: nil, - }, - ByzantineValidators: nil, - }) + beginBlockRequest := abci.RequestBeginBlock{ + Hash: hash[:], + Header: abciHeader, + LastCommitInfo: abci.LastCommitInfo{ + Round: 0, + Votes: nil, + }, + ByzantineValidators: nil, + } + abciResponses.BeginBlock, err = e.proxyApp.BeginBlockSync(beginBlockRequest) + if err != nil { + return nil, err + } + + err = genAndGossipFraudProofIfNeeded(&beginBlockRequest, nil, nil) if err != nil { return nil, err } + deliverTxRequests := make([]*abci.RequestDeliverTx, len(block.Data.Txs)) for _, tx := range block.Data.Txs { - res := e.proxyApp.DeliverTxAsync(abci.RequestDeliverTx{Tx: tx}) + deliverTxRequest := abci.RequestDeliverTx{Tx: tx} + deliverTxRequests = append(deliverTxRequests, &deliverTxRequest) + res := e.proxyApp.DeliverTxAsync(deliverTxRequest) if res.GetException() != nil { return nil, errors.New(res.GetException().GetError()) } + + err = genAndGossipFraudProofIfNeeded(&beginBlockRequest, deliverTxRequests, nil) + if err != nil { + return nil, err + } + } + endBlockRequest := abci.RequestEndBlock{Height: int64(block.Header.Height)} + abciResponses.EndBlock, err = e.proxyApp.EndBlockSync(endBlockRequest) + if err != nil { + return nil, err } - abciResponses.EndBlock, err = e.proxyApp.EndBlockSync(abci.RequestEndBlock{Height: int64(block.Header.Height)}) + err = genAndGossipFraudProofIfNeeded(&beginBlockRequest, deliverTxRequests, &endBlockRequest) if err != nil { return nil, err } + if fraudProofsEnabled && block.Data.IntermediateStateRoots.RawRootsList == nil { + // Block producer: Initial ISRs generated here + block.Data.IntermediateStateRoots.RawRootsList = ISRs + } + return abciResponses, nil } +func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) bool { + if currentIsrs != nil { + stateIsr := currentIsrs[index] + if !bytes.Equal(stateIsr, generatedIsr) { + e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) + return true + } + } + return false +} + +func (e *BlockExecutor) generateFraudProof(beginBlockRequest *abci.RequestBeginBlock, deliverTxRequests []*abci.RequestDeliverTx, endBlockRequest *abci.RequestEndBlock) (*abci.FraudProof, error) { + generateFraudProofRequest := abci.RequestGenerateFraudProof{} + if beginBlockRequest == nil { + return nil, fmt.Errorf("begin block request cannot be a nil parameter") + } + generateFraudProofRequest.BeginBlockRequest = *beginBlockRequest + if deliverTxRequests != nil { + generateFraudProofRequest.DeliverTxRequests = deliverTxRequests + if endBlockRequest != nil { + generateFraudProofRequest.EndBlockRequest = endBlockRequest + } + } + resp, err := e.proxyApp.GenerateFraudProofSync(generateFraudProofRequest) + if err != nil { + return nil, err + } + if resp.FraudProof == nil { + return nil, fmt.Errorf("fraud proof generation failed") + } + return resp.FraudProof, nil +} + func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte { lastABCICommit := abciconv.ToABCICommit(lastCommit) if len(lastCommit.Signatures) == 1 { @@ -376,6 +483,14 @@ func (e *BlockExecutor) publishEvents(resp *tmstate.ABCIResponses, block *types. return err } +func (e *BlockExecutor) getAppHash() ([]byte, error) { + isrResp, err := e.proxyApp.GetAppHashSync(abci.RequestGetAppHash{}) + if err != nil { + return nil, err + } + return isrResp.AppHash, nil +} + func toRollmintTxs(txs tmtypes.Txs) types.Txs { rollmintTxs := make(types.Txs, len(txs)) for i := range txs { diff --git a/state/executor_test.go b/state/executor_test.go index 24add8b607..5bfb933a0b 100644 --- a/state/executor_test.go +++ b/state/executor_test.go @@ -81,9 +81,13 @@ func TestApplyBlock(t *testing.T) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) var mockAppHash []byte _, err := rand.Read(mockAppHash[:]) require.NoError(err) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{ + AppHash: mockAppHash[:], + }) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{ Data: mockAppHash[:], }) diff --git a/types/fraudproof.go b/types/fraudproof.go new file mode 100644 index 0000000000..268ff55a88 --- /dev/null +++ b/types/fraudproof.go @@ -0,0 +1,16 @@ +package types + +// Represents a single-round fraudProof +type FraudProof struct { + BlockHeight uint64 + StateWitness StateWitness +} + +type StateWitness struct { + WitnessData []WitnessData +} + +type WitnessData struct { + Key []byte + Value []byte +} diff --git a/types/pb/rollmint/rollmint.pb.go b/types/pb/rollmint/rollmint.pb.go index f4d191a3b0..ebd8c15038 100644 --- a/types/pb/rollmint/rollmint.pb.go +++ b/types/pb/rollmint/rollmint.pb.go @@ -462,6 +462,154 @@ func (m *Block) GetLastCommit() *Commit { return nil } +type FraudProof struct { + BlockHeight uint64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + StateWitness *StateWitness `protobuf:"bytes,2,opt,name=state_witness,json=stateWitness,proto3" json:"state_witness,omitempty"` +} + +func (m *FraudProof) Reset() { *m = FraudProof{} } +func (m *FraudProof) String() string { return proto.CompactTextString(m) } +func (*FraudProof) ProtoMessage() {} +func (*FraudProof) Descriptor() ([]byte, []int) { + return fileDescriptor_ed7ee25509332ba7, []int{6} +} +func (m *FraudProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FraudProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FraudProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FraudProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_FraudProof.Merge(m, src) +} +func (m *FraudProof) XXX_Size() int { + return m.Size() +} +func (m *FraudProof) XXX_DiscardUnknown() { + xxx_messageInfo_FraudProof.DiscardUnknown(m) +} + +var xxx_messageInfo_FraudProof proto.InternalMessageInfo + +func (m *FraudProof) GetBlockHeight() uint64 { + if m != nil { + return m.BlockHeight + } + return 0 +} + +func (m *FraudProof) GetStateWitness() *StateWitness { + if m != nil { + return m.StateWitness + } + return nil +} + +type StateWitness struct { + WitnessData []*WitnessData `protobuf:"bytes,1,rep,name=witness_data,json=witnessData,proto3" json:"witness_data,omitempty"` +} + +func (m *StateWitness) Reset() { *m = StateWitness{} } +func (m *StateWitness) String() string { return proto.CompactTextString(m) } +func (*StateWitness) ProtoMessage() {} +func (*StateWitness) Descriptor() ([]byte, []int) { + return fileDescriptor_ed7ee25509332ba7, []int{7} +} +func (m *StateWitness) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StateWitness) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StateWitness.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StateWitness) XXX_Merge(src proto.Message) { + xxx_messageInfo_StateWitness.Merge(m, src) +} +func (m *StateWitness) XXX_Size() int { + return m.Size() +} +func (m *StateWitness) XXX_DiscardUnknown() { + xxx_messageInfo_StateWitness.DiscardUnknown(m) +} + +var xxx_messageInfo_StateWitness proto.InternalMessageInfo + +func (m *StateWitness) GetWitnessData() []*WitnessData { + if m != nil { + return m.WitnessData + } + return nil +} + +type WitnessData struct { + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *WitnessData) Reset() { *m = WitnessData{} } +func (m *WitnessData) String() string { return proto.CompactTextString(m) } +func (*WitnessData) ProtoMessage() {} +func (*WitnessData) Descriptor() ([]byte, []int) { + return fileDescriptor_ed7ee25509332ba7, []int{8} +} +func (m *WitnessData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WitnessData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WitnessData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WitnessData) XXX_Merge(src proto.Message) { + xxx_messageInfo_WitnessData.Merge(m, src) +} +func (m *WitnessData) XXX_Size() int { + return m.Size() +} +func (m *WitnessData) XXX_DiscardUnknown() { + xxx_messageInfo_WitnessData.DiscardUnknown(m) +} + +var xxx_messageInfo_WitnessData proto.InternalMessageInfo + +func (m *WitnessData) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *WitnessData) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + func init() { proto.RegisterType((*Version)(nil), "rollmint.Version") proto.RegisterType((*Header)(nil), "rollmint.Header") @@ -469,50 +617,59 @@ func init() { proto.RegisterType((*SignedHeader)(nil), "rollmint.SignedHeader") proto.RegisterType((*Data)(nil), "rollmint.Data") proto.RegisterType((*Block)(nil), "rollmint.Block") + proto.RegisterType((*FraudProof)(nil), "rollmint.FraudProof") + proto.RegisterType((*StateWitness)(nil), "rollmint.StateWitness") + proto.RegisterType((*WitnessData)(nil), "rollmint.WitnessData") } func init() { proto.RegisterFile("rollmint/rollmint.proto", fileDescriptor_ed7ee25509332ba7) } var fileDescriptor_ed7ee25509332ba7 = []byte{ - // 593 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0xc1, 0x6e, 0xd3, 0x4c, - 0x10, 0xc7, 0xeb, 0x26, 0x4d, 0xd2, 0x49, 0xbe, 0x7e, 0xe9, 0x0a, 0x15, 0x97, 0x4a, 0xa6, 0x58, - 0x42, 0x2a, 0x20, 0x25, 0x6a, 0x11, 0x12, 0x57, 0x0a, 0x48, 0x45, 0xdc, 0x5c, 0x89, 0x03, 0x97, - 0x68, 0x63, 0x8f, 0xec, 0x15, 0xb6, 0x77, 0xb5, 0xbb, 0xa9, 0xe0, 0x0d, 0xe0, 0xc6, 0xeb, 0xf0, - 0x06, 0x1c, 0x7b, 0xe4, 0x88, 0xda, 0x17, 0x41, 0x3b, 0xeb, 0xd8, 0xa9, 0xc4, 0x81, 0x4b, 0xb4, - 0xfb, 0xff, 0xff, 0x32, 0x3b, 0x33, 0x9e, 0x5d, 0xb8, 0xaf, 0x65, 0x59, 0x56, 0xa2, 0xb6, 0xf3, - 0xf5, 0x62, 0xa6, 0xb4, 0xb4, 0x92, 0x8d, 0xd6, 0xfb, 0x07, 0x47, 0x16, 0xeb, 0x0c, 0x35, 0x41, - 0x7c, 0x99, 0x8a, 0xb9, 0xfd, 0xa2, 0xd0, 0x78, 0x2c, 0x3e, 0x85, 0xe1, 0x07, 0xd4, 0x46, 0xc8, - 0x9a, 0xdd, 0x83, 0x9d, 0x65, 0x29, 0xd3, 0x4f, 0x61, 0x70, 0x1c, 0x9c, 0xf4, 0x13, 0xbf, 0x61, - 0x53, 0xe8, 0x71, 0xa5, 0xc2, 0x6d, 0xd2, 0xdc, 0x32, 0xfe, 0xd1, 0x83, 0xc1, 0x05, 0xf2, 0x0c, - 0x35, 0x7b, 0x06, 0xc3, 0x2b, 0xff, 0x6f, 0xfa, 0xd3, 0xf8, 0x6c, 0x7f, 0xd6, 0xa6, 0xd1, 0x84, - 0x4d, 0xd6, 0x04, 0x7b, 0x04, 0x93, 0x9a, 0x57, 0x68, 0x14, 0x4f, 0x71, 0x21, 0x32, 0x0a, 0x39, - 0x49, 0xc6, 0xad, 0xf6, 0x2e, 0x63, 0x07, 0x30, 0x28, 0x50, 0xe4, 0x85, 0x0d, 0x7b, 0x74, 0x5e, - 0xb3, 0x63, 0x0c, 0xfa, 0x56, 0x54, 0x18, 0xf6, 0x49, 0xa5, 0x35, 0x3b, 0x81, 0x69, 0xc9, 0x8d, - 0x5d, 0x14, 0x94, 0xca, 0xa2, 0xe0, 0xa6, 0x08, 0x77, 0x28, 0xe4, 0x9e, 0xd3, 0x7d, 0x86, 0x17, - 0xdc, 0x14, 0x2d, 0x99, 0xca, 0xaa, 0x12, 0xd6, 0x93, 0x83, 0x8e, 0x7c, 0x4d, 0x32, 0x91, 0x47, - 0xb0, 0x9b, 0x71, 0xcb, 0x3d, 0x32, 0x24, 0x64, 0xe4, 0x04, 0x32, 0x1f, 0xc3, 0x5e, 0x2a, 0x6b, - 0x83, 0xb5, 0x59, 0x19, 0x4f, 0x8c, 0x88, 0xf8, 0xaf, 0x55, 0x09, 0x3b, 0x84, 0x11, 0x57, 0xca, - 0x03, 0xbb, 0x04, 0x0c, 0xb9, 0x52, 0x64, 0x3d, 0x85, 0x7d, 0x4a, 0x44, 0xa3, 0x59, 0x95, 0xb6, - 0x09, 0x02, 0xc4, 0xfc, 0xef, 0x8c, 0xc4, 0xeb, 0xc4, 0x3e, 0x81, 0xa9, 0xd2, 0x52, 0x49, 0x83, - 0x7a, 0xc1, 0xb3, 0x4c, 0xa3, 0x31, 0xe1, 0xd8, 0xa3, 0x6b, 0xfd, 0x95, 0x97, 0x1d, 0xca, 0xf3, - 0x5c, 0x63, 0xce, 0xad, 0xd4, 0x4d, 0xd4, 0x89, 0x47, 0x37, 0x74, 0x17, 0x35, 0xe6, 0x30, 0xf0, - 0xe5, 0x6e, 0xb4, 0x3a, 0xb8, 0xd3, 0xea, 0x87, 0x30, 0xde, 0xec, 0xa8, 0xff, 0x48, 0x50, 0x74, - 0xdd, 0x8c, 0x00, 0x8c, 0xc8, 0x6b, 0x6e, 0x57, 0x1a, 0x4d, 0xd8, 0x3b, 0xee, 0x39, 0xbf, 0x53, - 0xe2, 0x25, 0x4c, 0x2e, 0x45, 0x5e, 0x63, 0xd6, 0xcc, 0xc8, 0x89, 0x3b, 0xc8, 0xad, 0x9a, 0x11, - 0x99, 0x76, 0x23, 0xe2, 0x89, 0xa4, 0xf1, 0x1d, 0xe9, 0x3f, 0x11, 0x9d, 0x7a, 0x87, 0xf4, 0x49, - 0x27, 0x8d, 0x1f, 0x7f, 0x0b, 0xa0, 0xff, 0x86, 0x5b, 0xee, 0xa6, 0xd3, 0x7e, 0x36, 0x61, 0x40, - 0x59, 0xb8, 0x25, 0x7b, 0x09, 0xa1, 0xa8, 0x2d, 0xea, 0x0a, 0x33, 0xc1, 0x2d, 0x2e, 0x8c, 0x75, - 0xbf, 0x5a, 0x4a, 0x6b, 0xc2, 0x6d, 0xc2, 0x0e, 0x36, 0xfd, 0x4b, 0x67, 0x27, 0xce, 0x65, 0x2f, - 0x60, 0x84, 0x57, 0x22, 0xc3, 0x3a, 0x45, 0x2a, 0x6b, 0x7c, 0x76, 0x38, 0xeb, 0xae, 0xce, 0xcc, - 0x5d, 0x9d, 0xd9, 0xdb, 0x06, 0x48, 0x5a, 0x34, 0xfe, 0x1a, 0xc0, 0xce, 0x39, 0x5d, 0x95, 0x7f, - 0xaf, 0x34, 0x86, 0xbe, 0x1b, 0xab, 0xa6, 0xce, 0xbd, 0x8e, 0x73, 0x45, 0x25, 0xe4, 0xb1, 0x53, - 0x18, 0x6f, 0x4c, 0x2d, 0x5d, 0x88, 0xbf, 0xb5, 0x04, 0xba, 0x11, 0x3e, 0x7f, 0xff, 0xf3, 0x26, - 0x0a, 0xae, 0x6f, 0xa2, 0xe0, 0xf7, 0x4d, 0x14, 0x7c, 0xbf, 0x8d, 0xb6, 0xae, 0x6f, 0xa3, 0xad, - 0x5f, 0xb7, 0xd1, 0xd6, 0xc7, 0xd3, 0x5c, 0xd8, 0x62, 0xb5, 0x9c, 0xa5, 0xb2, 0x9a, 0xa7, 0x58, - 0xa2, 0xb1, 0x82, 0x4b, 0x9d, 0xb7, 0x8f, 0x86, 0x7f, 0x13, 0xe6, 0x6a, 0xd9, 0x2a, 0xcb, 0x01, - 0x3d, 0x10, 0xcf, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xff, 0x4f, 0x18, 0x98, 0x62, 0x04, 0x00, - 0x00, + // 691 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0xdf, 0x6a, 0xd4, 0x40, + 0x14, 0xc6, 0x9b, 0xee, 0x76, 0x77, 0x7b, 0x92, 0xd6, 0x6d, 0xd0, 0x9a, 0x5a, 0x88, 0x35, 0x20, + 0x54, 0x85, 0x5d, 0x5a, 0x29, 0x14, 0xbc, 0xb2, 0xfe, 0x61, 0xc5, 0x1b, 0x49, 0x41, 0xc1, 0x9b, + 0x30, 0x9b, 0x8c, 0xc9, 0xd0, 0x24, 0x13, 0x66, 0x66, 0x5b, 0xfb, 0x06, 0x7a, 0xe7, 0xeb, 0xf8, + 0x06, 0x5e, 0xf6, 0xd2, 0x4b, 0x69, 0x5f, 0x44, 0xe6, 0x4c, 0x36, 0x49, 0xc1, 0x0b, 0x6f, 0x96, + 0x99, 0xef, 0xfb, 0xed, 0xc9, 0x39, 0x67, 0xce, 0x0c, 0xdc, 0x17, 0x3c, 0xcf, 0x0b, 0x56, 0xaa, + 0xe9, 0x72, 0x31, 0xa9, 0x04, 0x57, 0xdc, 0x1d, 0x2d, 0xf7, 0x0f, 0x76, 0x15, 0x2d, 0x13, 0x2a, + 0x10, 0x22, 0xf3, 0x98, 0x4d, 0xd5, 0x65, 0x45, 0xa5, 0xc1, 0x82, 0x03, 0x18, 0x7e, 0xa4, 0x42, + 0x32, 0x5e, 0xba, 0x77, 0x61, 0x6d, 0x9e, 0xf3, 0xf8, 0xcc, 0xb3, 0xf6, 0xac, 0xfd, 0x7e, 0x68, + 0x36, 0xee, 0x18, 0x7a, 0xa4, 0xaa, 0xbc, 0x55, 0xd4, 0xf4, 0x32, 0xf8, 0xd9, 0x83, 0xc1, 0x8c, + 0x92, 0x84, 0x0a, 0xf7, 0x19, 0x0c, 0xcf, 0xcd, 0xbf, 0xf1, 0x4f, 0xf6, 0xe1, 0xd6, 0xa4, 0x49, + 0xa3, 0x0e, 0x1b, 0x2e, 0x09, 0xf7, 0x11, 0x38, 0x25, 0x29, 0xa8, 0xac, 0x48, 0x4c, 0x23, 0x96, + 0x60, 0x48, 0x27, 0xb4, 0x1b, 0xed, 0x5d, 0xe2, 0x6e, 0xc3, 0x20, 0xa3, 0x2c, 0xcd, 0x94, 0xd7, + 0xc3, 0xef, 0xd5, 0x3b, 0xd7, 0x85, 0xbe, 0x62, 0x05, 0xf5, 0xfa, 0xa8, 0xe2, 0xda, 0xdd, 0x87, + 0x71, 0x4e, 0xa4, 0x8a, 0x32, 0x4c, 0x25, 0xca, 0x88, 0xcc, 0xbc, 0x35, 0x0c, 0xb9, 0xa9, 0x75, + 0x93, 0xe1, 0x8c, 0xc8, 0xac, 0x21, 0x63, 0x5e, 0x14, 0x4c, 0x19, 0x72, 0xd0, 0x92, 0xaf, 0x50, + 0x46, 0x72, 0x17, 0xd6, 0x13, 0xa2, 0x88, 0x41, 0x86, 0x88, 0x8c, 0xb4, 0x80, 0xe6, 0x63, 0xd8, + 0x8c, 0x79, 0x29, 0x69, 0x29, 0x17, 0xd2, 0x10, 0x23, 0x24, 0x36, 0x1a, 0x15, 0xb1, 0x1d, 0x18, + 0x91, 0xaa, 0x32, 0xc0, 0x3a, 0x02, 0x43, 0x52, 0x55, 0x68, 0x3d, 0x85, 0x2d, 0x4c, 0x44, 0x50, + 0xb9, 0xc8, 0x55, 0x1d, 0x04, 0x90, 0xb9, 0xa3, 0x8d, 0xd0, 0xe8, 0xc8, 0x3e, 0x81, 0x71, 0x25, + 0x78, 0xc5, 0x25, 0x15, 0x11, 0x49, 0x12, 0x41, 0xa5, 0xf4, 0x6c, 0x83, 0x2e, 0xf5, 0x97, 0x46, + 0xd6, 0x28, 0x49, 0x53, 0x41, 0x53, 0xa2, 0xb8, 0xa8, 0xa3, 0x3a, 0x06, 0xed, 0xe8, 0x3a, 0x6a, + 0x40, 0x60, 0x60, 0xca, 0xed, 0xb4, 0xda, 0xba, 0xd5, 0xea, 0x87, 0x60, 0x77, 0x3b, 0x6a, 0x0e, + 0x09, 0xb2, 0xb6, 0x9b, 0x3e, 0x80, 0x64, 0x69, 0x49, 0xd4, 0x42, 0x50, 0xe9, 0xf5, 0xf6, 0x7a, + 0xda, 0x6f, 0x95, 0x60, 0x0e, 0xce, 0x29, 0x4b, 0x4b, 0x9a, 0xd4, 0x33, 0xb2, 0xaf, 0x3f, 0xa4, + 0x57, 0xf5, 0x88, 0x8c, 0xdb, 0x11, 0x31, 0x44, 0x58, 0xfb, 0x9a, 0x34, 0x47, 0x84, 0x5f, 0xbd, + 0x45, 0x9a, 0xa4, 0xc3, 0xda, 0x0f, 0xbe, 0x5b, 0xd0, 0x7f, 0x4d, 0x14, 0xd1, 0xd3, 0xa9, 0xbe, + 0x4a, 0xcf, 0xc2, 0x2c, 0xf4, 0xd2, 0x3d, 0x06, 0x8f, 0x95, 0x8a, 0x8a, 0x82, 0x26, 0x8c, 0x28, + 0x1a, 0x49, 0xa5, 0x7f, 0x05, 0xe7, 0x4a, 0x7a, 0xab, 0x88, 0x6d, 0x77, 0xfd, 0x53, 0x6d, 0x87, + 0xda, 0x75, 0x8f, 0x60, 0x44, 0xcf, 0x59, 0x42, 0xcb, 0x98, 0x62, 0x59, 0xf6, 0xe1, 0xce, 0xa4, + 0xbd, 0x3a, 0x13, 0x7d, 0x75, 0x26, 0x6f, 0x6a, 0x20, 0x6c, 0xd0, 0xe0, 0x9b, 0x05, 0x6b, 0x27, + 0x78, 0x55, 0xfe, 0xbf, 0xd2, 0x00, 0xfa, 0x7a, 0xac, 0xea, 0x3a, 0x37, 0x5b, 0x4e, 0x17, 0x15, + 0xa2, 0xe7, 0x1e, 0x80, 0xdd, 0x99, 0x5a, 0xbc, 0x10, 0xff, 0x6a, 0x09, 0xb4, 0x23, 0x1c, 0xe4, + 0x00, 0x6f, 0x05, 0x59, 0x24, 0x1f, 0x04, 0xe7, 0x5f, 0xf4, 0x7d, 0xc3, 0x2b, 0x1c, 0xdd, 0x3a, + 0x67, 0x1b, 0xb5, 0x99, 0x39, 0xec, 0x17, 0xb0, 0x61, 0xfa, 0x73, 0xc1, 0x54, 0xa9, 0x27, 0xcc, + 0x24, 0xb4, 0xdd, 0x7e, 0x05, 0xfb, 0xf3, 0xc9, 0xb8, 0xa1, 0x23, 0x3b, 0xbb, 0x60, 0x06, 0x4e, + 0xd7, 0x75, 0x8f, 0xc1, 0xa9, 0xc3, 0x44, 0x58, 0x9c, 0x85, 0x3d, 0xbc, 0xd7, 0xc6, 0xaa, 0x41, + 0xac, 0xd1, 0xbe, 0x68, 0x37, 0xc1, 0x11, 0xd8, 0x1d, 0x4f, 0x1f, 0xea, 0x19, 0xbd, 0xc4, 0x7c, + 0x9d, 0x50, 0x2f, 0xf5, 0xd3, 0x74, 0x4e, 0xf2, 0x05, 0xad, 0xc7, 0xd1, 0x6c, 0x4e, 0xde, 0xff, + 0xba, 0xf6, 0xad, 0xab, 0x6b, 0xdf, 0xfa, 0x73, 0xed, 0x5b, 0x3f, 0x6e, 0xfc, 0x95, 0xab, 0x1b, + 0x7f, 0xe5, 0xf7, 0x8d, 0xbf, 0xf2, 0xf9, 0x20, 0x65, 0x2a, 0x5b, 0xcc, 0x27, 0x31, 0x2f, 0xa6, + 0x31, 0xcd, 0xa9, 0x54, 0x8c, 0x70, 0x91, 0x36, 0x6f, 0xa4, 0x79, 0x02, 0xa7, 0xd5, 0xbc, 0x51, + 0xe6, 0x03, 0x7c, 0x0f, 0x9f, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x11, 0x93, 0x50, 0x4e, 0x51, + 0x05, 0x00, 0x00, } func (m *Version) Marshal() (dAtA []byte, err error) { @@ -861,6 +1018,120 @@ func (m *Block) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *FraudProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FraudProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FraudProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.StateWitness != nil { + { + size, err := m.StateWitness.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollmint(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.BlockHeight != 0 { + i = encodeVarintRollmint(dAtA, i, uint64(m.BlockHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *StateWitness) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StateWitness) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StateWitness) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WitnessData) > 0 { + for iNdEx := len(m.WitnessData) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.WitnessData[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollmint(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *WitnessData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WitnessData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WitnessData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintRollmint(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintRollmint(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintRollmint(dAtA []byte, offset int, v uint64) int { offset -= sovRollmint(v) base := offset @@ -1029,6 +1300,54 @@ func (m *Block) Size() (n int) { return n } +func (m *FraudProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlockHeight != 0 { + n += 1 + sovRollmint(uint64(m.BlockHeight)) + } + if m.StateWitness != nil { + l = m.StateWitness.Size() + n += 1 + l + sovRollmint(uint64(l)) + } + return n +} + +func (m *StateWitness) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.WitnessData) > 0 { + for _, e := range m.WitnessData { + l = e.Size() + n += 1 + l + sovRollmint(uint64(l)) + } + } + return n +} + +func (m *WitnessData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovRollmint(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovRollmint(uint64(l)) + } + return n +} + func sovRollmint(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2116,6 +2435,313 @@ func (m *Block) Unmarshal(dAtA []byte) error { } return nil } +func (m *FraudProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FraudProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FraudProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + m.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StateWitness", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollmint + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollmint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StateWitness == nil { + m.StateWitness = &StateWitness{} + } + if err := m.StateWitness.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollmint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollmint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StateWitness) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StateWitness: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StateWitness: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WitnessData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollmint + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollmint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WitnessData = append(m.WitnessData, &WitnessData{}) + if err := m.WitnessData[len(m.WitnessData)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollmint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollmint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WitnessData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WitnessData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WitnessData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRollmint + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRollmint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollmint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRollmint + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRollmint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollmint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollmint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRollmint(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/types/serialization.go b/types/serialization.go index d42a4d99ca..43e035a5e1 100644 --- a/types/serialization.go +++ b/types/serialization.go @@ -41,6 +41,85 @@ func (h *Header) UnmarshalBinary(data []byte) error { return err } +// MarshalBinary encodes Header into binary form and returns it. +func (fp *FraudProof) MarshalBinary() ([]byte, error) { + return fp.ToProto().Marshal() +} + +// UnmarshalBinary decodes binary form of Header into object. +func (fp *FraudProof) UnmarshalBinary(data []byte) error { + var pFraudProof pb.FraudProof + err := pFraudProof.Unmarshal(data) + if err != nil { + return err + } + err = fp.FromProto(&pFraudProof) + return err +} + +// ToProto converts Fraud Proof into protobuf representation and returns it. +func (fp *FraudProof) ToProto() *pb.FraudProof { + return &pb.FraudProof{ + BlockHeight: fp.BlockHeight, + StateWitness: fp.StateWitness.ToProto(), + } +} + +// FromProto fills Block with data from its protobuf representation. +func (fp *FraudProof) FromProto(other *pb.FraudProof) error { + var err error + fp.BlockHeight = other.BlockHeight + err = fp.StateWitness.FromProto(other.StateWitness) + return err +} + +// ToProto converts Witness Data into protobuf representation and returns it. +func (wd *WitnessData) ToProto() *pb.WitnessData { + return &pb.WitnessData{ + Key: wd.Key[:], + Value: wd.Value[:], + } +} + +// FromProto converts Witness Data from protobuf representation and returns it. +func (wd *WitnessData) FromProto(other *pb.WitnessData) error { + wd.Key = other.Key + wd.Value = other.Value + return nil +} + +func witnessesFromProto(sw *pb.StateWitness) ([]WitnessData, error) { + var witnesses []WitnessData + for _, wd := range sw.WitnessData { + var witnessData WitnessData + err := witnessData.FromProto(wd) + if err != nil { + return nil, err + } + witnesses = append(witnesses, witnessData) + } + return witnesses, nil +} + +// ToProto converts State Witness into protobuf representation and returns it. +func (sw *StateWitness) ToProto() *pb.StateWitness { + var witnessData []*pb.WitnessData + for _, wd := range sw.WitnessData { + witnessData = append(witnessData, wd.ToProto()) + } + return &pb.StateWitness{WitnessData: witnessData} +} + +// FromProto fills State Witness Data from its protobuf representation and returns it. +func (stateWitness *StateWitness) FromProto(other *pb.StateWitness) error { + witnesses, err := witnessesFromProto(other) + if err != nil { + return err + } + stateWitness.WitnessData = witnesses[:] + return nil +} + // MarshalBinary encodes Data into binary form and returns it. func (d *Data) MarshalBinary() ([]byte, error) { return d.ToProto().Marshal() diff --git a/types/serialization_test.go b/types/serialization_test.go index 63124e6d44..2761edb4d9 100644 --- a/types/serialization_test.go +++ b/types/serialization_test.go @@ -185,6 +185,40 @@ func TestStateRoundTrip(t *testing.T) { } } +func TestFraudProofSerializationRoundTrip(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + input *FraudProof + }{ + {"fp", &FraudProof{ + BlockHeight: 1234, + StateWitness: StateWitness{ + WitnessData: []WitnessData{ + {Key: []byte{1, 2}, Value: []byte{3, 4}}, + {Key: []byte{5, 6}, Value: []byte{7, 8}}, + }, + }, + }, + }} + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + assert := assert.New(t) + blob, err := c.input.MarshalBinary() + assert.NoError(err) + assert.NotEmpty(blob) + + deserialized := &FraudProof{} + err = deserialized.UnmarshalBinary(blob) + assert.NoError(err) + + assert.Equal(c.input, deserialized) + }) + } +} + // copied from store_test.go func getRandomValidatorSet() *tmtypes.ValidatorSet { pubKey := ed25519.GenPrivKey().PubKey()