Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index malleated transactions properly #612

Merged
merged 8 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ OUTPUT?=build/tendermint

BUILD_TAGS?=tendermint

IMAGE := ghcr.io/tendermint/docker-build-proto:latest
DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE)

# If building a release, please checkout the version tag to get the correct version setting
ifneq ($(shell git symbolic-ref -q --short HEAD),)
VERSION := unreleased-$(shell git symbolic-ref -q --short HEAD)-$(shell git rev-parse HEAD)
Expand All @@ -13,7 +16,6 @@ endif
LD_FLAGS = -X github.com/tendermint/tendermint/version.TMCoreSemVer=$(VERSION)
BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)"
HTTPS_GIT := https://github.com/tendermint/tendermint.git
DOCKER_BUF := docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf
CGO_ENABLED ?= 0

# handle nostrip
Expand Down Expand Up @@ -74,30 +76,29 @@ install:
### Protobuf ###
###############################################################################

proto-all: proto-gen proto-lint proto-check-breaking
proto-all: proto-lint proto-check-breaking
.PHONY: proto-all

proto-gen:
@docker pull -q tendermintdev/docker-build-proto
@echo "Generating Protobuf files"
@docker run -v $(shell pwd):/workspace --workdir /workspace tendermintdev/docker-build-proto sh ./scripts/protocgen.sh
@$(DOCKER_PROTO_BUILDER) buf generate --template=./buf.gen.yaml --config ./buf.yaml
.PHONY: proto-gen

proto-lint:
@$(DOCKER_BUF) check lint --error-format=json
@$(DOCKER_PROTO_BUILDER) buf lint --error-format=json --config ./buf.yaml
.PHONY: proto-lint

proto-format:
@echo "Formatting Protobuf files"
docker run -v $(shell pwd):/workspace --workdir /workspace tendermintdev/docker-build-proto find ./ -not -path "./third_party/*" -name *.proto -exec clang-format -i {} \;
@$(DOCKER_PROTO_BUILDER) find . -name '*.proto' -path "./proto/*" -exec clang-format -i {} \;
.PHONY: proto-format

proto-check-breaking:
@$(DOCKER_BUF) check breaking --against-input .git#branch=master
@$(DOCKER_PROTO_BUILDER) buf breaking --against .git --config ./buf.yaml
.PHONY: proto-check-breaking

proto-check-breaking-ci:
@$(DOCKER_BUF) check breaking --against-input $(HTTPS_GIT)#branch=master
@$(DOCKER_PROTO_BUILDER) buf breaking --against $(HTTPS_GIT) --config ./buf.yaml
.PHONY: proto-check-breaking-ci

###############################################################################
Expand Down
2 changes: 1 addition & 1 deletion abci/types/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons
}

func (BaseApplication) PreprocessTxs(req RequestPreprocessTxs) ResponsePreprocessTxs {
return ResponsePreprocessTxs{}
return ResponsePreprocessTxs{Txs: req.Txs}
Copy link
Member Author

@evan-forbes evan-forbes Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this took entirely too long to debug... not that it matters too much cause upstream removed these tests in #6685 😆 🙃

app tests should be fixed

}

//-------------------------------------------------------
Expand Down
417 changes: 236 additions & 181 deletions abci/types/types.pb.go

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions proto/tendermint/abci/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ message ResponseDeliverTx {
int64 gas_wanted = 5 [json_name = "gas_wanted"];
int64 gas_used = 6 [json_name = "gas_used"];
repeated Event events = 7
[(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic
[(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic
string codespace = 8;
}

Expand Down Expand Up @@ -334,10 +334,11 @@ message EventAttribute {
//
// One usage is indexing transaction results.
message TxResult {
int64 height = 1;
uint32 index = 2;
bytes tx = 3;
ResponseDeliverTx result = 4 [(gogoproto.nullable) = false];
int64 height = 1;
uint32 index = 2;
bytes tx = 3;
ResponseDeliverTx result = 4 [(gogoproto.nullable) = false];
bytes original_hash = 5;
}

//----------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions proto/tendermint/da/data_availability_header.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ option go_package = "github.com/tendermint/tendermint/proto/tendermint/da";
// Note that currently we list row and column roots in separate fields
// (different from the spec).
message DataAvailabilityHeader {
// RowRoot_j = root((M_{j,1} || M_{j,2} || ... || M_{j,2k} ))
repeated bytes row_roots = 1;
// ColumnRoot_j = root((M_{1,j} || M_{2,j} || ... || M_{2k,j} ))
repeated bytes column_roots = 2;
}
// RowRoot_j = root((M_{j,1} || M_{j,2} || ... || M_{j,2k} ))
repeated bytes row_roots = 1;
// ColumnRoot_j = root((M_{1,j} || M_{2,j} || ... || M_{2k,j} ))
repeated bytes column_roots = 2;
}
6 changes: 3 additions & 3 deletions proto/tendermint/types/block.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "gogoproto/gogo.proto";
import "tendermint/types/types.proto";

message Block {
Header header = 1 [(gogoproto.nullable) = false];
Data data = 2 [(gogoproto.nullable) = false];
Commit last_commit = 4;
Header header = 1 [(gogoproto.nullable) = false];
Data data = 2 [(gogoproto.nullable) = false];
Commit last_commit = 4;
}
14 changes: 7 additions & 7 deletions proto/tendermint/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ message Data {
repeated bytes txs = 1;

IntermediateStateRoots intermediate_state_roots = 2 [(gogoproto.nullable) = false];
EvidenceList evidence = 3 [(gogoproto.nullable) = false];
Messages messages = 4 [(gogoproto.nullable) = false];
EvidenceList evidence = 3 [(gogoproto.nullable) = false];
Messages messages = 4 [(gogoproto.nullable) = false];
}

// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes.
Expand Down Expand Up @@ -170,10 +170,10 @@ message Vote {

// Commit contains the evidence that a block was committed by a set of validators.
message Commit {
int64 height = 1;
int32 round = 2;
BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"];
repeated CommitSig signatures = 4 [(gogoproto.nullable) = false];
int64 height = 1;
int32 round = 2;
BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"];
repeated CommitSig signatures = 4 [(gogoproto.nullable) = false];
}

// CommitSig is a part of the Vote included in a Commit.
Expand Down Expand Up @@ -225,5 +225,5 @@ message TxProof {
// transactions
message MalleatedTx {
bytes original_tx_hash = 1;
bytes tx = 2;
bytes tx = 2;
}
19 changes: 15 additions & 4 deletions state/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,11 +548,22 @@ func fireEvents(
}

for i, tx := range block.Data.Txs {
var txHash []byte
var rawTx []byte
if originalHash, malleatedTx, ismalleated := types.UnwrapMalleatedTx(tx); ismalleated {
txHash = originalHash
rawTx = malleatedTx
} else {
txHash = tx.Hash()
rawTx = tx
}

if err := eventBus.PublishEventTx(types.EventDataTx{TxResult: abci.TxResult{
Height: block.Height,
Index: uint32(i),
Tx: tx,
Result: *(abciResponses.DeliverTxs[i]),
Height: block.Height,
Index: uint32(i),
Tx: rawTx,
Result: *(abciResponses.DeliverTxs[i]),
OriginalHash: txHash,
}}); err != nil {
logger.Error("failed publishing event TX", "err", err)
}
Expand Down
76 changes: 36 additions & 40 deletions state/txindex/kv/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
dbm "github.com/tendermint/tm-db"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/libs/pubsub/query"
"github.com/tendermint/tendermint/state/indexer"
"github.com/tendermint/tendermint/state/txindex"
Expand Down Expand Up @@ -69,26 +70,7 @@ func (txi *TxIndex) AddBatch(b *txindex.Batch) error {
defer storeBatch.Close()

for _, result := range b.Ops {
hash := types.Tx(result.Tx).Hash()

// index tx by events
err := txi.indexEvents(result, hash, storeBatch)
if err != nil {
return err
}

// index by height (always)
err = storeBatch.Set(keyForHeight(result), hash)
if err != nil {
return err
}

rawBytes, err := proto.Marshal(result)
if err != nil {
return err
}
// index by hash (always)
err = storeBatch.Set(hash, rawBytes)
err := txi.indexResult(storeBatch, result)
if err != nil {
return err
}
Expand All @@ -105,26 +87,7 @@ func (txi *TxIndex) Index(result *abci.TxResult) error {
b := txi.store.NewBatch()
defer b.Close()

hash := types.Tx(result.Tx).Hash()

// index tx by events
err := txi.indexEvents(result, hash, b)
if err != nil {
return err
}

// index by height (always)
err = b.Set(keyForHeight(result), hash)
if err != nil {
return err
}

rawBytes, err := proto.Marshal(result)
if err != nil {
return err
}
// index by hash (always)
err = b.Set(hash, rawBytes)
err := txi.indexResult(b, result)
if err != nil {
return err
}
Expand Down Expand Up @@ -158,6 +121,39 @@ func (txi *TxIndex) indexEvents(result *abci.TxResult, hash []byte, store dbm.Ba
return nil
}

func (txi *TxIndex) indexResult(batch dbm.Batch, result *abci.TxResult) error {
var hash []byte
if len(result.OriginalHash) == tmhash.Size {
hash = result.OriginalHash
} else {
hash = types.Tx(result.Tx).Hash()
}

rawBytes, err := proto.Marshal(result)
if err != nil {
return err
}

// index tx by events
err = txi.indexEvents(result, hash, batch)
if err != nil {
return err
}

// index by height (always)
err = batch.Set(keyForHeight(result), hash)
if err != nil {
return err
}

// index by hash (always)
err = batch.Set(hash, rawBytes)
if err != nil {
return err
}
return nil
}

// Search performs a search using the given query.
//
// It breaks the query into conditions (like "tx.height > 5"). For each
Expand Down
45 changes: 45 additions & 0 deletions state/txindex/kv/kv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,51 @@ func TestTxIndex(t *testing.T) {
assert.True(t, proto.Equal(txResult2, loadedTxResult2))
}

func TestMalleatedTxIndex(t *testing.T) {
type test struct {
tx types.Tx
originalHash []byte
expectedTx []byte
}
originalTx1 := types.Tx([]byte("ORIGINAL_TX"))
malleatedTx1 := types.Tx([]byte("MALLEATED_TX"))

tests := []test{
// we expect to get the malleated tx returned when searching using the original hash
{
tx: malleatedTx1,
originalHash: originalTx1.Hash(),
expectedTx: malleatedTx1,
},
}

indexer := NewTxIndex(db.NewMemDB())

for i, tt := range tests {

txResult := &abci.TxResult{
Height: int64(i),
Index: 0,
Tx: tt.tx,
Result: abci.ResponseDeliverTx{
Data: []byte{0},
Code: abci.CodeTypeOK, Log: "", Events: nil,
},
OriginalHash: tt.originalHash,
}
batch := txindex.NewBatch(1)
if err := batch.Add(txResult); err != nil {
t.Error(err)
}
err := indexer.AddBatch(batch)
require.NoError(t, err)

loadedTxResult, err := indexer.Get(tt.originalHash)
require.NoError(t, err)
assert.Equal(t, tt.expectedTx, loadedTxResult.Tx)
}
}

func TestTxSearch(t *testing.T) {
indexer := NewTxIndex(db.NewMemDB())

Expand Down
6 changes: 3 additions & 3 deletions types/event_bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/libs/log"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
"github.com/tendermint/tendermint/libs/service"
Expand Down Expand Up @@ -178,9 +179,8 @@ func (b *EventBus) PublishEventTx(data EventDataTx) error {
ctx := context.Background()

var txHash []byte
if originalHash, malleated, ismalleated := UnwrapMalleatedTx(data.Tx); ismalleated {
txHash = originalHash
data.Tx = malleated
if len(data.OriginalHash) == tmhash.Size {
txHash = data.OriginalHash
} else {
txHash = Tx(data.Tx).Hash()
}
Expand Down
11 changes: 5 additions & 6 deletions types/event_bus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ func TestEventBusPublishEventMalleatedTx(t *testing.T) {

tx := Tx("foo")
malleatedTx := Tx("foo-malleated")
wrappedMalleatedTx, err := WrapMalleatedTx(tx.Hash(), malleatedTx)
require.NoError(t, err)

result := abci.ResponseDeliverTx{
Data: []byte("bar"),
Expand All @@ -104,10 +102,11 @@ func TestEventBusPublishEventMalleatedTx(t *testing.T) {
}()

err = eventBus.PublishEventTx(EventDataTx{abci.TxResult{
Height: 1,
Index: 0,
Tx: wrappedMalleatedTx,
Result: result,
Height: 1,
Index: 0,
Tx: malleatedTx,
Result: result,
OriginalHash: tx.Hash(),
}})
assert.NoError(t, err)

Expand Down