-
Notifications
You must be signed in to change notification settings - Fork 46
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
Cron ticker implementation #837
Conversation
Generated by 🚫 Danger |
We should run each in a separate CacheWrap like we do with |
Let's update this. As of tendermint 0.14 or whenever I wrote this, BeginBlock returned nothing. It now returns tags: https://github.com/tendermint/tendermint/blob/v0.31.5/abci/types/types.proto#L167-L169 I would then allow DeliverResult response. We can use an error to signal discarding the cachewrap (similar to Savepoint Decorator). And from the positive result, just include the tags in the BeginBlock return value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice start and good queue design.
Some comments to help proceed
queue/queue.go
Outdated
if ok, err := db.Has(key); err != nil { | ||
return errors.Wrap(err, "cannot check key existance") | ||
} else if ok { | ||
// If the key is already in use, instead of storing a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Fair tradeoff. We need to ensure this queue cannot be spammed in any case
queue/queue.go
Outdated
// it := db.Iterate(since, until) | ||
// ... | ||
|
||
// TODO: iterate from 0 a.d. till now and return the first message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a good approach. Clear TODO comment
queue/queue.go
Outdated
|
||
func queueKey(t time.Time) []byte { | ||
rawTime := make([]byte, 8) | ||
binary.BigEndian.PutUint64(rawTime, uint64(t.UnixNano())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nanosecond? We could round off to second.
That limits how many messages can be processed per block to 1/second of block time. Which is actually a nice feature in my opinion.
Either is fine, just comment on the precision
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added the comment and changed the granularity to second in 3c31063
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mentioned needing some reliable id to identify these issues. Does it need to be a primary key with an index based on time? Or can we just add some arbitrary "id" label to the payload (not just Msg)?
Let us think a bit more on this one. You also realize
var msg Msg
msg.Unmarshal(data)
will always fail, as we need a concrete instance... which means we need some oneof casting here. (This is the reason go-amino allows runtime registration on interfaces. It does make coding in go easier, but at the cost of an undocumented and unmaintainable api for the client)
queue/queue.go
Outdated
// Put queues the message in the database to be executed at given time. | ||
// Due to the implementation details, message is guaranteed to be executed | ||
// after given time, but not exactly at given time. | ||
func Put(db weave.KVStore, runAt time.Time, msg weave.Msg) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good.
I like serializing the msg and registering a handler (similar to gov).
Thinking this through, I realized something is missing and I have no clear way forward.... Authentication info (aka context). Is there a way to serialize context (using interface keys, I highly doubt it)?
We need to know what authority the transaction has when executed, and things like TextResolutionMsg must have other context, like the successful proposal that triggered it. You can complete this PR and merge without context, but it is essential to support serialized authorization somehow. I admit that is a large problem, so just getting a working queue merged in is a great step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I serialize a transaction instead? This way there is no difference between executing a transaction straight away and executing with a delay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context is not the actual transaction. Transactions encapsulate requests coming from outside the blockchain. All items here originated inside the blockchain, from a trusted module. That means we don't need to evaluate signatures, but do need a way to capture all context.
I reflected some on #822 (comment) and while I had an adverse reaction to storing auth info like that, as it is no longer tied to any modules (insecure), if we do just run trusted modules and pin/audit their codebase, someone entering fake credentials should not be a real issue. And we can just store the contexts in a straight-forward method to remove much complexity.
This example would allow us to just serialize the AuthN []Condition
or AuthN []Address
items and reuse them on a new transaction. Maybe we should revisit this PR with an expanded request interface that makes it easy to do so?
x/cron/cron.go
Outdated
|
||
taskCtx := ctx | ||
if prep, ok := task.(ContextPreparer); ok { | ||
taskCtx = prep.Prepare(taskCtx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ethanfrey I am trying to figure out a good way to insert authentication (and other) information into the context. My latest approach is to delegate this to the client.
I have realized that this cannot be delegated to the client completely, because it is heavily dependent on the authentication used by the router. To keep things simple I was planning to use the same router as the rest of the application. This means, that the same sigs
and multisig
authentication is required.
I wonder if it would not be best to use the same technique for the Task
implementation - create a message with middleware fields like multisig
and signatures
and use extension decorators to work with them. This make the whole functionality very much like a synchronous request handling, which is good.
The problem with this approach is that extension cannot set Task
attributes because it does not know about the implementation. 🤔
I feel a bit like I am going in circles with this implementation. I did many improvements compared to the initial version, but now I slowed down and don't quite know how to solve the context issue.
Implement a message cron ticker. This is an incomplete implementation. I want to show my approach first to make sure it is correct before writing the implementation. There are some decistions I had to make that I am not sure they were the right ones. 1. When scheduling a task, we schedule a message for later execution. When time will come, a phony transaction containing this message is executed. 2. Because I am using a phony transaction, no transaction attributes can be enforced. 3. All messages are executed in a single transaction. This means that a single broken message can stop the whole queue from progressing. 4. All handler responses are ignored as the `weave.Ticker` interface does not return almost anything on success.
This comment has been minimized.
This comment has been minimized.
Briefly looked over this - the approach seems good to me. |
I am closing this draft as a I have created a new pull request using a cleaned up commits #850 |
Implement a message cron ticker.
This is an incomplete implementation. I want to show my approach first
to make sure it is correct before writing the implementation.
There are some decistions I had to make that I am not sure they were the
right ones.
When time will come, a phony transaction containing this message is
executed.
be enforced.
single broken message can stop the whole queue from progressing.
weave.Ticker
interfacedoes not return almost anything on success.
This is work necessary for #671