Skip to content

Commit

Permalink
feat: replace nonce system with timestamp TTL-based replay protection (
Browse files Browse the repository at this point in the history
…#801)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Zulkhair Abdullah Daim <[email protected]>
  • Loading branch information
3 people authored Oct 30, 2024
1 parent 5b45feb commit 5f45c7c
Show file tree
Hide file tree
Showing 55 changed files with 2,338 additions and 461 deletions.
1 change: 1 addition & 0 deletions .run/World Engine Docker - Test Game Debug.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<option value="nakama" />
<option value="redis" />
<option value="game-debug" />
<option value="test_nakama" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
Expand Down
15 changes: 15 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,18 @@ docker compose test_nakama up
```

and watch those tests run again. You should get the same output.

## Submitting Changes

Before you push changes, including creating or updating a pull request, please be sure you have done the following
steps to be sure that your PR will pass the CI tests. These command are run from the `world-engine` directory.

```shell
make lint
make unit-test-all
make e2e-nakama
make e2e-evm
```

If any of those fail, you can be sure your push will fail to pass the CI tests, and you should fix those issues before
pushing to origin.
3 changes: 1 addition & 2 deletions cardinal/cardinal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,7 @@ func TestCreatePersona(t *testing.T) {
}
wantBody, err := json.Marshal(body)
assert.NilError(t, err)
wantNonce := uint64(100)
sp, err := sign.NewSystemTransaction(goodKey, namespace, wantNonce, wantBody)
sp, err := sign.NewSystemTransaction(goodKey, namespace, wantBody)
assert.NilError(t, err)
bodyBytes, err := json.Marshal(sp)
assert.NilError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions cardinal/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ func TestRecoverFromChain(t *testing.T) {
},
},
Tick: 1,
Timestamp: uint64(time.Now().Unix()),
Timestamp: uint64(sign.TimestampNow()),
},
{
Batches: []*iterator.TxBatch{
Expand All @@ -484,7 +484,7 @@ func TestRecoverFromChain(t *testing.T) {
},
},
Tick: 15,
Timestamp: uint64(time.Now().Unix()),
Timestamp: uint64(sign.TimestampNow()),
},
}

Expand Down
13 changes: 9 additions & 4 deletions cardinal/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ module pkg.world.dev/world-engine/cardinal

go 1.22.1

replace pkg.world.dev/world-engine/sign => ../sign

replace pkg.world.dev/world-engine/rift => ../rift

require (
github.com/alecthomas/participle/v2 v2.1.0
github.com/alicebob/miniredis/v2 v2.30.5
github.com/argus-labs/go-jobqueue v0.1.6
github.com/coocood/freecache v1.2.4
github.com/ethereum/go-ethereum v1.13.10
github.com/fasthttp/websocket v1.5.8
github.com/goccy/go-json v0.10.3
Expand All @@ -30,12 +35,12 @@ require (
go.opentelemetry.io/otel/trace v1.26.0
golang.org/x/sync v0.6.0
google.golang.org/grpc v1.63.2
google.golang.org/protobuf v1.33.0
google.golang.org/protobuf v1.35.1
gopkg.in/DataDog/dd-trace-go.v1 v1.63.1
gotest.tools/v3 v3.5.1
pkg.world.dev/world-engine/assert v1.0.0
pkg.world.dev/world-engine/rift v1.1.0-beta.0.20240402214846-de1fc179818a
pkg.world.dev/world-engine/sign v1.0.1-beta
pkg.world.dev/world-engine/rift v1.2.0
pkg.world.dev/world-engine/sign v1.1.0
)

require (
Expand Down Expand Up @@ -121,7 +126,7 @@ require (
go.opentelemetry.io/otel/metric v1.26.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.23.0 // indirect
Expand Down
54 changes: 46 additions & 8 deletions cardinal/go.sum

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions cardinal/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ func WithDisableSignatureVerification() WorldOption {
}
}

// WithMessageExpiration How long messages will live past their creation
// time on the sender before they are considered to be expired and will
// not be processed. Default is 10 seconds.
// For longer expiration times you may also need to set a larger hash cache
// size using the WithHashCacheSize option
// This setting is ignored if the DisableSignatureVerification option is used
// NOTE: this means that the real time clock for the sender and receiver
// must be synchronized
func WithMessageExpiration(seconds int) WorldOption {
return WorldOption{
serverOption: server.WithMessageExpiration(seconds),
}
}

// WithTickChannel sets the channel that will be used to decide when world.doTick is executed. If unset, a loop interval
// of 1 second will be set. To set some other time, use: WithTickChannel(time.Tick(<some-duration>)). Tests can pass
// in a channel controlled by the test for fine-grained control over when ticks are executed.
Expand Down
2 changes: 1 addition & 1 deletion cardinal/router/iterator/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func protoTxToSignTx(t *shard.Transaction) *sign.Transaction {
tx := &sign.Transaction{
PersonaTag: t.GetPersonaTag(),
Namespace: t.GetNamespace(),
Nonce: t.GetNonce(),
Timestamp: t.GetTimestamp(),
Signature: t.GetSignature(),
Hash: common.Hash{},
Body: t.GetBody(),
Expand Down
8 changes: 5 additions & 3 deletions cardinal/router/iterator/iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/binary"
"errors"
"testing"
"time"

"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -102,7 +103,7 @@ func TestIteratorHappyPath(t *testing.T) {
protoTx := &shard.Transaction{
PersonaTag: "ty",
Namespace: namespace,
Nonce: 1,
Timestamp: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli(),
Signature: "fo",
Body: msgBytes,
}
Expand Down Expand Up @@ -146,6 +147,7 @@ func TestIteratorHappyPath(t *testing.T) {
assert.Equal(t, tx.MsgValue, msgValue)
assert.Equal(t, tx.MsgID, fooMsg.ID())
assert.Equal(t, tx.Tx.PersonaTag, protoTx.GetPersonaTag())
assert.Equal(t, tx.Tx.Timestamp, time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli())
assert.True(t, len(tx.Tx.Hash.Bytes()) > 1)
assert.Equal(t, tx.Tx.Namespace, namespace)
assert.DeepEqual(t, []byte(tx.Tx.Body), msgBytes)
Expand All @@ -159,7 +161,7 @@ func TestIteratorStartRange(t *testing.T) {
querier := &mockQuerier{retErr: errors.New("whatever")}
it := iterator.New(nil, "", querier)

// we dont care about this error, we're just checking if `querier` gets called with the right key in the Page.
// we don't care about this error, we're just checking if `querier` gets called with the right key in the Page.
startRange := uint64(5)
_ = it.Each(nil, 5)

Expand All @@ -178,7 +180,7 @@ func TestIteratorStopRange(t *testing.T) {
protoTx := &shard.Transaction{
PersonaTag: "ty",
Namespace: namespace,
Nonce: 1,
Timestamp: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli(),
Signature: "fo",
Body: msgBytes,
}
Expand Down
2 changes: 1 addition & 1 deletion cardinal/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (r *router) SubmitTxBlob(
protoTxs = append(protoTxs, &shard.Transaction{
PersonaTag: tx.PersonaTag,
Namespace: tx.Namespace,
Nonce: tx.Nonce,
Timestamp: tx.Timestamp,
Signature: tx.Signature,
Body: tx.Body,
})
Expand Down
2 changes: 1 addition & 1 deletion cardinal/server/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ const docTemplate = `{
"namespace": {
"type": "string"
},
"nonce": {
"timestamp": {
"type": "integer"
},
"personaTag": {
Expand Down
10 changes: 6 additions & 4 deletions cardinal/server/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -469,13 +469,15 @@
"description": "json string",
"type": "object"
},
"hash": {
"type": "string"
},
"namespace": {
"type": "string"
},
"nonce": {
"timestamp": {
"description": "Unix timestamp, in milliseconds, for TTL-based replay protection.",
"type": "integer"
},
"salt": {
"description": "optional additional randomness for hash and signing",
"type": "integer"
},
"personaTag": {
Expand Down
9 changes: 6 additions & 3 deletions cardinal/server/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,15 @@ definitions:
body:
description: json string
type: object
hash:
type: string
namespace:
type: string
nonce:
timestamp:
description: Unix timestamp, in milliseconds, for TTL-based replay protection.
type: integer
salt:
description: optional additional randomness for hash and signing
type: integer
required: false
personaTag:
type: string
signature:
Expand Down
Loading

0 comments on commit 5f45c7c

Please sign in to comment.