Skip to content
This repository has been archived by the owner on Jul 15, 2018. It is now read-only.

Tags in DeliverTx response #130

Merged
merged 42 commits into from
Nov 27, 2017
Merged

Tags in DeliverTx response #130

merged 42 commits into from
Nov 27, 2017

Conversation

melekes
Copy link
Contributor

@melekes melekes commented Nov 9, 2017

No description provided.

Copy link
Contributor

@ebuchman ebuchman left a comment

Choose a reason for hiding this comment

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

Thanks for linting!

What's your thinking behind value_int ? Why not just have the string value ? If there are things we know we need numbers for, like gas, we should probably just build those in direct.

@melekes
Copy link
Contributor Author

melekes commented Nov 14, 2017

If there are things we know we need numbers for, like gas, we should probably just build those in direct.

my thinking was by declaring a type we're avoiding parsing errors. For example, tag "count_participants": 5. And the user wants to query "count_participants > 3". If value were a string ("5"), we'd have to parse it as Int each time and then compare against the query. If the value is an int, we're avoiding parsing (protobuf ensures it is an int64) and can also save it as int in the DB. But maybe this is not worth adding a new field.

message KVPair {
  string key = 1;
  string value_string = 2;
  int64 value_int = 3;
}

@ebuchman
Copy link
Contributor

Interesting. I'm not sure if it's worth it. What does @ethanfrey think?

@melekes
Copy link
Contributor Author

melekes commented Nov 14, 2017

Originally this design was suggested by Jae.

@melekes
Copy link
Contributor Author

melekes commented Nov 15, 2017

message KVPair {
  enum Type { STRING = 1; INT = 2; }
  
  string Key = 1;

  Type type = 2;
  string ValueString = 3;
  int64 ValueInt = 4;
}

we can also add a type so we could switch in code ^^^ and later extend it with other types (like Date or Time). use case is when user wants to pass "" as a value

@ethanfrey
Copy link
Contributor

ethanfrey commented Nov 16, 2017

I originally proposed a list of strings and only doing exact matches. thus it would match a specific key-value pair.

This concept was turned much more complex to the string-{string,int} model proposed in a meeting with anton, jae, and bucky. And was the last consensus in the design document: https://gist.github.com/melekes/131291e5144e31d34ac3ed3ab7ff2aca#gistcomment-2127313

AFAIK, the only use cases of the queries needed by the API are for exact matches, and if we are not using integer comparison (does anyone really need to filter all tx with a value over 40 atom regardless of address?), I am fine using only string equality (i can encode addresses as strings).

If we do support both int and strings and comparison operators in the indexer, however, it does make sense to expose that in the abci api.

Given the design space that was agreed upon, I approve this pr, but please use different result types here:
https://github.com/tendermint/abci/blob/feature/tags-in-deliver-tx/types/application.go#L16
and here:
https://github.com/tendermint/abci/blob/feature/tags-in-deliver-tx/types/application.go#L21

Copy link
Contributor

@ethanfrey ethanfrey left a comment

Choose a reason for hiding this comment

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

I think we need to separate out DeliverTx and CheckTx, otherwise, the implementation looks good.

types/result.go Outdated
@@ -102,6 +103,7 @@ func (r *ResponseCheckTx) Result() Result {
Code: r.Code,
Data: r.Data,
Log: r.Log,
Tags: r.Tags,
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no meaning to tags in checktx, as they should never be indexed. We should remove that from the api, as it would be misleading.

types/result.go Outdated
@@ -12,6 +12,7 @@ type Result struct {
Code CodeType `json:"code"`
Data data.Bytes `json:"data"`
Log string `json:"log"` // Can be non-deterministic
Tags []*KVPair `json:"tags"`
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should start separating the result from DeliverTx and CheckTx.
DeliverTx needs tags, which CheckTx doesn't.
We will also need to add Gas and Fees (or Cost and Value or....) to CheckTx as per #57 and soon.

Given this, I already separated the DeliverTx and CheckTx results in the sdk. We should use different types in the abci.

@melekes
Copy link
Contributor Author

melekes commented Nov 16, 2017

I don't think it's too late to switch to Redis like subscriptions in that is what we want and it is enough for everyone.

@ethanfrey
Copy link
Contributor

Added comments on slack, but they belong here:

We actually don't need any general purpose > < and strings are fine for subscriptions.
We only need to add a special case height int that supports < and > just for search, not subscriptions.

If we actually used redis as a backing store for pub sub (just as an example, we don't need to), sorted sets would satisfy the requirements of exactly one, predefined integer sort:

https://redis.io/topics/data-types#sorted-sets
https://redis.io/commands/zrangebyscore

This technique is explained in detail here (just skip the java code in the middle):

https://www.infoworld.com/article/3212768/database/how-to-use-redis-for-real-time-stream-processing.html?page=2

I am not saying we have to use redis as a backing store (although I think it might be nice to support it as an optional backend), but more illustrating that if we simplify the requirements to string channels and search by (exact channel, min height, max height), it becomes a much simpler problem to implement, as redis is a very simple k-v store.

I could also implement this sorted set query pattern on top of level db without much problem, and as anton has already implemented pubsub, that would cover the requirements.

@ethanfrey
Copy link
Contributor

ethanfrey commented Nov 17, 2017

btw, my approach for handling this directly on leveldb, which supports iteration, would be to define keys as (channel string, block uint64, index uint32) tuples, using uncompressed bigendian for the uints so their binary representation has the same lexographical order as an integer comparison. And prefixing string with the length to avoid overlap in searches between strings like "foo" and "foobar" (or another approach that acheives the same).

You could then calculate byte representations for (channel, min block, 0) and (channel, max block, MAX_UINT32) and run a level db iterator over that space. Super easy and efficient (edited)

The purpose of adding tx index as a third parameter is to avoid collisions if there are multiple tx in the same block that match a channel

@melekes
Copy link
Contributor Author

melekes commented Nov 17, 2017

I like that idea, but the question is that enough for UI? https://allinbits.slack.com/archives/C564C4P1U/p1510910368000182?thread_ts=1510859626.000247&cid=C564C4P1U

@melekes melekes changed the title WIP: tags Tags in DeliverTx response Nov 21, 2017
melekes added a commit to tendermint/tendermint that referenced this pull request Nov 23, 2017
@melekes
Copy link
Contributor Author

melekes commented Nov 23, 2017

Addressed all the comments.

func (app *BaseApplication) DeliverTx(tx []byte) Result {
return NewResultOK(nil, "")
func (BaseApplication) DeliverTx(tx []byte) ResponseDeliverTx {
return ResponseDeliverTx{Code: CodeType_OK}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

btw, why DeliverTx/CheckTx/Commit return OK, but Query returns empty ResponseQuery{}?

Copy link
Contributor

Choose a reason for hiding this comment

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

LOL good eye. Should be effectively the same since OK is the zero value, but we should be consistent.

melekes added a commit to tendermint/tendermint that referenced this pull request Nov 24, 2017
@@ -6,114 +6,47 @@ import (
"github.com/tendermint/go-wire/data"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we use the methods from this file anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, in Tendermint

}
}

// ResultQuery is a wrapper around ResponseQuery using data.Bytes instead of
// raw byte slices.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we still need it?

Makefile Outdated
@ bash tests/test.sh

test_race:
@ find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this line is needed for test_integrations!

@@ -1,57 +0,0 @@
package main
Copy link
Contributor Author

Choose a reason for hiding this comment

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

why remove this?

Copy link
Contributor

Choose a reason for hiding this comment

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

its not testing anything new. used to be when BlockAware was it's own interface. Now it's just part of Application.


FEATURES:
- [types] added Tags field to ResponseDeliverTx
- [types] added Gas and Fee fields to ResponseCheckTx
Copy link
Contributor Author

Choose a reason for hiding this comment

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

want to add this to readme?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes thanks for reminder!

test.sh Outdated
echo "==> Running integration tests (./tests)"
find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
make install
bash tests/test.sh
Copy link
Contributor Author

@melekes melekes Nov 27, 2017

Choose a reason for hiding this comment

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

actually, we can call make test_integrations here. this will allows us to remove redundant find . -path ... line and make install line

Copy link
Contributor

Choose a reason for hiding this comment

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

dont we want test_integrations to run the shell scripts too tho ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, i see. ok

@melekes
Copy link
Contributor Author

melekes commented Nov 27, 2017

@ebuchman ebuchman merged commit 460c045 into develop Nov 27, 2017
@ebuchman
Copy link
Contributor

BOOM

@ebuchman ebuchman deleted the feature/tags-in-deliver-tx branch November 27, 2017 22:42
melekes added a commit to tendermint/tendermint that referenced this pull request Nov 28, 2017
melekes added a commit to tendermint/tendermint that referenced this pull request Nov 29, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants