mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 23:02:16 +00:00
namereg cleanup, tests
This commit is contained in:
parent
02aedaaefb
commit
77ff09e173
@ -197,30 +197,41 @@ func testNameReg(t *testing.T, typ string) {
|
|||||||
con.Close()
|
con.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
types.MinNameRegistrationPeriod = 1
|
||||||
|
|
||||||
// register a new name, check if its there
|
// register a new name, check if its there
|
||||||
amt, fee := uint64(6969), uint64(1000)
|
|
||||||
// since entries ought to be unique and these run against different clients, we append the typ
|
// since entries ought to be unique and these run against different clients, we append the typ
|
||||||
name := "ye_old_domain_name_" + typ
|
name := "ye_old_domain_name_" + typ
|
||||||
data := "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need"
|
data := "if not now, when"
|
||||||
|
fee := uint64(1000)
|
||||||
|
numDesiredBlocks := uint64(2)
|
||||||
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
|
|
||||||
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
|
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
|
||||||
broadcastTx(t, typ, tx)
|
broadcastTx(t, typ, tx)
|
||||||
|
// commit block
|
||||||
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
||||||
mempoolCount = 0
|
mempoolCount = 0
|
||||||
entry := getNameRegEntry(t, typ, name)
|
entry := getNameRegEntry(t, typ, name)
|
||||||
if entry.Data != data {
|
if entry.Data != data {
|
||||||
t.Fatal(fmt.Sprintf("Got %s, expected %s", entry.Data, data))
|
t.Fatal(fmt.Sprintf("Err on entry.Data: Got %s, expected %s", entry.Data, data))
|
||||||
|
}
|
||||||
|
if bytes.Compare(entry.Owner, user[0].Address) != 0 {
|
||||||
|
t.Fatal(fmt.Sprintf("Err on entry.Owner: Got %s, expected %s", entry.Owner, user[0].Address))
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the data as the owner, make sure still there
|
// update the data as the owner, make sure still there
|
||||||
data = "if not now, when"
|
numDesiredBlocks = uint64(2)
|
||||||
|
data = "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need"
|
||||||
|
amt = fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx = makeDefaultNameTx(t, typ, name, data, amt, fee)
|
tx = makeDefaultNameTx(t, typ, name, data, amt, fee)
|
||||||
broadcastTx(t, typ, tx)
|
broadcastTx(t, typ, tx)
|
||||||
|
// commit block
|
||||||
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
||||||
mempoolCount = 0
|
mempoolCount = 0
|
||||||
entry = getNameRegEntry(t, typ, name)
|
entry = getNameRegEntry(t, typ, name)
|
||||||
if entry.Data != data {
|
if entry.Data != data {
|
||||||
t.Fatal(fmt.Sprintf("Got %s, expected %s", entry.Data, data))
|
t.Fatal(fmt.Sprintf("Err on entry.Data: Got %s, expected %s", entry.Data, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to update as non owner, should fail
|
// try to update as non owner, should fail
|
||||||
@ -232,4 +243,19 @@ func testNameReg(t *testing.T, typ string) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expected error on NameTx")
|
t.Fatal("Expected error on NameTx")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// commit block
|
||||||
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
||||||
|
|
||||||
|
// now the entry should be expired, so we can update as non owner
|
||||||
|
_, err = client.BroadcastTx(tx)
|
||||||
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
||||||
|
mempoolCount = 0
|
||||||
|
entry = getNameRegEntry(t, typ, name)
|
||||||
|
if entry.Data != data2 {
|
||||||
|
t.Fatal(fmt.Sprintf("Error on entry.Data: Got %s, expected %s", entry.Data, data2))
|
||||||
|
}
|
||||||
|
if bytes.Compare(entry.Owner, user[1].Address) != 0 {
|
||||||
|
t.Fatal(fmt.Sprintf("Err on entry.Owner: Got %s, expected %s", entry.Owner, user[1].Address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,18 +505,20 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate the input strings
|
// validate the input strings
|
||||||
if !tx.Validate() {
|
if err := tx.ValidateStrings(); err != nil {
|
||||||
log.Debug(Fmt("Invalid characters present in NameTx name (%s) or data (%s)", tx.Name, tx.Data))
|
log.Debug(err.Error())
|
||||||
return types.ErrTxInvalidString
|
return types.ErrTxInvalidString
|
||||||
}
|
}
|
||||||
|
|
||||||
value := tx.Input.Amount - tx.Fee
|
value := tx.Input.Amount - tx.Fee
|
||||||
|
|
||||||
// let's say cost of a name for one block is len(data) + 32
|
// let's say cost of a name for one block is len(data) + 32
|
||||||
costPerBlock := uint64(len(tx.Data) + 32)
|
costPerBlock := types.NameCostPerBlock * types.NameCostPerByte * tx.BaseEntryCost()
|
||||||
expiresIn := value / uint64(costPerBlock)
|
expiresIn := value / uint64(costPerBlock)
|
||||||
lastBlockHeight := uint64(_s.LastBlockHeight)
|
lastBlockHeight := uint64(_s.LastBlockHeight)
|
||||||
|
|
||||||
|
log.Debug("New NameTx", "value", value, "costPerBlock", costPerBlock, "expiresIn", expiresIn, "lastBlock", lastBlockHeight)
|
||||||
|
|
||||||
// check if the name exists
|
// check if the name exists
|
||||||
entry := blockCache.GetNameRegEntry(tx.Name)
|
entry := blockCache.GetNameRegEntry(tx.Name)
|
||||||
|
|
||||||
@ -537,26 +539,36 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
if value == 0 && len(tx.Data) == 0 {
|
if value == 0 && len(tx.Data) == 0 {
|
||||||
// maybe we reward you for telling us we can delete this crap
|
// maybe we reward you for telling us we can delete this crap
|
||||||
// (owners if not expired, anyone if expired)
|
// (owners if not expired, anyone if expired)
|
||||||
|
log.Debug("Removing namereg entry", "name", entry.Name)
|
||||||
blockCache.RemoveNameRegEntry(entry.Name)
|
blockCache.RemoveNameRegEntry(entry.Name)
|
||||||
} else {
|
} else {
|
||||||
// update the entry by bumping the expiry
|
// update the entry by bumping the expiry
|
||||||
// and changing the data
|
// and changing the data
|
||||||
if expired {
|
if expired {
|
||||||
|
if expiresIn < types.MinNameRegistrationPeriod {
|
||||||
|
return fmt.Errorf("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)
|
||||||
|
}
|
||||||
entry.Expires = lastBlockHeight + expiresIn
|
entry.Expires = lastBlockHeight + expiresIn
|
||||||
|
entry.Owner = tx.Input.Address
|
||||||
|
log.Debug("An old namereg entry has expired and been reclaimed", "name", entry.Name, "expiresIn", expiresIn, "owner", entry.Owner)
|
||||||
} else {
|
} else {
|
||||||
// since the size of the data may have changed
|
// since the size of the data may have changed
|
||||||
// we use the total amount of "credit"
|
// we use the total amount of "credit"
|
||||||
credit := (entry.Expires - lastBlockHeight) * uint64(len(entry.Data))
|
oldCredit := (entry.Expires - lastBlockHeight) * types.BaseEntryCost(entry.Name, entry.Data)
|
||||||
credit += value
|
credit := oldCredit + value
|
||||||
expiresIn = credit / costPerBlock
|
expiresIn = credit / costPerBlock
|
||||||
|
if expiresIn < types.MinNameRegistrationPeriod {
|
||||||
|
return fmt.Errorf("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)
|
||||||
|
}
|
||||||
entry.Expires = lastBlockHeight + expiresIn
|
entry.Expires = lastBlockHeight + expiresIn
|
||||||
|
log.Debug("Updated namereg entry", "name", entry.Name, "expiresIn", expiresIn, "oldCredit", oldCredit, "value", value, "credit", credit)
|
||||||
}
|
}
|
||||||
entry.Data = tx.Data
|
entry.Data = tx.Data
|
||||||
blockCache.UpdateNameRegEntry(entry)
|
blockCache.UpdateNameRegEntry(entry)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if expiresIn < 5 {
|
if expiresIn < types.MinNameRegistrationPeriod {
|
||||||
return fmt.Errorf("Names must be registered for at least 5 blocks")
|
return fmt.Errorf("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)
|
||||||
}
|
}
|
||||||
// entry does not exist, so create it
|
// entry does not exist, so create it
|
||||||
entry = &types.NameRegEntry{
|
entry = &types.NameRegEntry{
|
||||||
@ -565,6 +577,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
Data: tx.Data,
|
Data: tx.Data,
|
||||||
Expires: lastBlockHeight + expiresIn,
|
Expires: lastBlockHeight + expiresIn,
|
||||||
}
|
}
|
||||||
|
log.Debug("Creating namereg entry", "name", entry.Name, "expiresIn", expiresIn)
|
||||||
blockCache.UpdateNameRegEntry(entry)
|
blockCache.UpdateNameRegEntry(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,15 @@ func execTxWithState(state *State, tx types.Tx, runCall bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func execTxWithStateNewBlock(state *State, tx types.Tx, runCall bool) error {
|
||||||
|
if err := execTxWithState(state, tx, runCall); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
state.LastBlockHeight += 1
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestCopyState(t *testing.T) {
|
func TestCopyState(t *testing.T) {
|
||||||
// Generate a random state
|
// Generate a random state
|
||||||
s0, privAccounts, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
|
s0, privAccounts, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
|
||||||
@ -166,26 +175,6 @@ func TestTxSequence(t *testing.T) {
|
|||||||
acc0PubKey := privAccounts[0].PubKey
|
acc0PubKey := privAccounts[0].PubKey
|
||||||
acc1 := state.GetAccount(privAccounts[1].PubKey.Address())
|
acc1 := state.GetAccount(privAccounts[1].PubKey.Address())
|
||||||
|
|
||||||
// Try executing a SendTx with various sequence numbers.
|
|
||||||
makeSendTx := func(sequence uint) *types.SendTx {
|
|
||||||
return &types.SendTx{
|
|
||||||
Inputs: []*types.TxInput{
|
|
||||||
&types.TxInput{
|
|
||||||
Address: acc0.Address,
|
|
||||||
Amount: 1,
|
|
||||||
Sequence: sequence,
|
|
||||||
PubKey: acc0PubKey,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []*types.TxOutput{
|
|
||||||
&types.TxOutput{
|
|
||||||
Address: acc1.Address,
|
|
||||||
Amount: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test a variety of sequence numbers for the tx.
|
// Test a variety of sequence numbers for the tx.
|
||||||
// The tx should only pass when i == 1.
|
// The tx should only pass when i == 1.
|
||||||
for i := -1; i < 3; i++ {
|
for i := -1; i < 3; i++ {
|
||||||
@ -220,6 +209,130 @@ func TestTxSequence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNameTxs(t *testing.T) {
|
||||||
|
state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
|
||||||
|
|
||||||
|
types.MinNameRegistrationPeriod = 5
|
||||||
|
startingBlock := uint64(state.LastBlockHeight)
|
||||||
|
|
||||||
|
// try some bad names. these should all fail
|
||||||
|
names := []string{"", "\n", "123#$%", "\x00", string([]byte{20, 40, 60, 80}), "baffledbythespectacleinallofthisyouseeehesaidwithouteyes", "no spaces please"}
|
||||||
|
data := "something about all this just doesn't feel right."
|
||||||
|
fee := uint64(1000)
|
||||||
|
numDesiredBlocks := uint64(5)
|
||||||
|
for _, name := range names {
|
||||||
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[0])
|
||||||
|
|
||||||
|
if err := execTxWithState(state, tx, true); err == nil {
|
||||||
|
t.Fatalf("Expected invalid name error from %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try some bad data. these should all fail
|
||||||
|
name := "hold_it_chum"
|
||||||
|
datas := []string{"cold&warm", "!@#$%^&*()", "<<<>>>>", "because why would you ever need a ~ or a & or even a % in a json file? make your case and we'll talk"}
|
||||||
|
for _, data := range datas {
|
||||||
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[0])
|
||||||
|
|
||||||
|
if err := execTxWithState(state, tx, true); err == nil {
|
||||||
|
t.Fatalf("Expected invalid data error from %s", data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEntry := func(t *testing.T, entry *types.NameRegEntry, name, data string, addr []byte, expires uint64) {
|
||||||
|
|
||||||
|
if entry == nil {
|
||||||
|
t.Fatalf("Could not find name %s", name)
|
||||||
|
}
|
||||||
|
if bytes.Compare(entry.Owner, addr) != 0 {
|
||||||
|
t.Fatalf("Wrong owner. Got %X expected %X", entry.Owner, addr)
|
||||||
|
}
|
||||||
|
if data != entry.Data {
|
||||||
|
t.Fatalf("Wrong data. Got %s expected %s", entry.Data, data)
|
||||||
|
}
|
||||||
|
if name != entry.Name {
|
||||||
|
t.Fatalf("Wrong name. Got %s expected %s", entry.Name, name)
|
||||||
|
}
|
||||||
|
if expires != entry.Expires {
|
||||||
|
t.Fatalf("Wrong expiry. Got %d, expected %d", entry.Expires, expires)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try a good one, check data, owner, expiry
|
||||||
|
name = "looking_good/karaoke_bar"
|
||||||
|
data = "on this side of neptune there are 1234567890 people: first is OMNIVORE. Or is it. Ok this is pretty restrictive. No exclamations :(. Faces tho :')"
|
||||||
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[0])
|
||||||
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
entry := state.GetNameRegEntry(name)
|
||||||
|
validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks)
|
||||||
|
|
||||||
|
// fail to update it as non-owner, in same block
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[1])
|
||||||
|
if err := execTxWithState(state, tx, true); err == nil {
|
||||||
|
t.Fatal("Expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// update it as owner, just to increase expiry, in same block
|
||||||
|
// NOTE: we have to resend the data or it will clear it (is this what we want?)
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[0])
|
||||||
|
if err := execTxWithStateNewBlock(state, tx, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
entry = state.GetNameRegEntry(name)
|
||||||
|
validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*2)
|
||||||
|
|
||||||
|
// update it as owner, just to increase expiry, in next block
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[0])
|
||||||
|
if err := execTxWithStateNewBlock(state, tx, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
entry = state.GetNameRegEntry(name)
|
||||||
|
validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*3)
|
||||||
|
|
||||||
|
// fail to update it as non-owner
|
||||||
|
state.LastBlockHeight = uint(entry.Expires - 1)
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[1])
|
||||||
|
if err := execTxWithState(state, tx, true); err == nil {
|
||||||
|
t.Fatal("Expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// once expires, non-owner succeeds
|
||||||
|
state.LastBlockHeight = uint(entry.Expires)
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[1])
|
||||||
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
entry = state.GetNameRegEntry(name)
|
||||||
|
validateEntry(t, entry, name, data, privAccounts[1].Address, uint64(state.LastBlockHeight)+numDesiredBlocks)
|
||||||
|
|
||||||
|
// update it as new owner, with new data (longer), but keep the expiry!
|
||||||
|
data = "In the beginning there was no thing, not even the beginning. It hadn't been here, no there, nor for that matter anywhere, not especially because it had not to even exist, let alone to not. Nothing especially odd about that."
|
||||||
|
oldCredit := amt - fee
|
||||||
|
numDesiredBlocks = 10
|
||||||
|
amt = fee + (numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data) - oldCredit)
|
||||||
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
|
tx.Sign(privAccounts[1])
|
||||||
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
entry = state.GetNameRegEntry(name)
|
||||||
|
validateEntry(t, entry, name, data, privAccounts[1].Address, uint64(state.LastBlockHeight)+numDesiredBlocks)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: test overflows.
|
// TODO: test overflows.
|
||||||
// TODO: test for unbonding validators.
|
// TODO: test for unbonding validators.
|
||||||
func TestTxs(t *testing.T) {
|
func TestTxs(t *testing.T) {
|
||||||
@ -268,7 +381,7 @@ func TestTxs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallTx.
|
// CallTx. Just runs through it and checks the transfer. See vm, rpc tests for more
|
||||||
{
|
{
|
||||||
state := state.Copy()
|
state := state.Copy()
|
||||||
newAcc1 := state.GetAccount(acc1.Address)
|
newAcc1 := state.GetAccount(acc1.Address)
|
||||||
|
@ -1,5 +1,40 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MinNameRegistrationPeriod uint64 = 5
|
||||||
|
|
||||||
|
// cost for storing a name for a block is
|
||||||
|
// CostPerBlock*CostPerByte*(len(data) + 32)
|
||||||
|
NameCostPerByte uint64 = 1
|
||||||
|
NameCostPerBlock uint64 = 1
|
||||||
|
|
||||||
|
MaxNameLength = 32
|
||||||
|
MaxDataLength = 1 << 16
|
||||||
|
|
||||||
|
// Name should be alphanum, underscore, slash
|
||||||
|
// Data should be anything permitted in JSON
|
||||||
|
regexpAlphaNum = regexp.MustCompile("^[a-zA-Z0-9_/]*$")
|
||||||
|
regexpJSON = regexp.MustCompile(`^[a-zA-Z0-9_/ \-"':,\n\t.{}()\[\]]*$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// filter strings
|
||||||
|
func validateNameRegEntryName(name string) bool {
|
||||||
|
return regexpAlphaNum.Match([]byte(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateNameRegEntryData(data string) bool {
|
||||||
|
return regexpJSON.Match([]byte(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// base cost is "effective" number of bytes
|
||||||
|
func BaseEntryCost(name, data string) uint64 {
|
||||||
|
return uint64(len(data) + 32)
|
||||||
|
}
|
||||||
|
|
||||||
type NameRegEntry struct {
|
type NameRegEntry struct {
|
||||||
Name string `json:"name"` // registered name for the entry
|
Name string `json:"name"` // registered name for the entry
|
||||||
Owner []byte `json:"owner"` // address that created the entry
|
Owner []byte `json:"owner"` // address that created the entry
|
||||||
|
30
types/tx.go
30
types/tx.go
@ -3,7 +3,6 @@ package types
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/account"
|
"github.com/tendermint/tendermint/account"
|
||||||
"github.com/tendermint/tendermint/binary"
|
"github.com/tendermint/tendermint/binary"
|
||||||
@ -200,15 +199,30 @@ func (tx *NameTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
|
|||||||
binary.WriteTo([]byte(`}]}`), w, n, err)
|
binary.WriteTo([]byte(`}]}`), w, n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// alphanum, underscore, forward slash
|
func (tx *NameTx) ValidateStrings() error {
|
||||||
var regexpAlphaNum, _ = regexp.Compile("^[a-zA-Z0-9_/]*$")
|
if len(tx.Name) == 0 {
|
||||||
|
return errors.New("Name must not be empty")
|
||||||
|
}
|
||||||
|
if len(tx.Name) > MaxNameLength {
|
||||||
|
return errors.New(Fmt("Name is too long. Max %d bytes", MaxNameLength))
|
||||||
|
}
|
||||||
|
if len(tx.Data) > MaxDataLength {
|
||||||
|
return errors.New(Fmt("Data is too long. Max %d bytes", MaxDataLength))
|
||||||
|
}
|
||||||
|
|
||||||
// anything you might find in a json
|
if !validateNameRegEntryName(tx.Name) {
|
||||||
var regexpJSON, err = regexp.Compile(`^[a-zA-Z0-9_/ \-"':,\n\t.{}()\[\]]*$`)
|
return errors.New(Fmt("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, and forward slashes allowed", tx.Name))
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *NameTx) Validate() bool {
|
if !validateNameRegEntryData(tx.Data) {
|
||||||
// Name should be alphanum and Data should be like JSON
|
return errors.New(Fmt("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data))
|
||||||
return regexpAlphaNum.Match([]byte(tx.Name)) && regexpJSON.Match([]byte(tx.Data))
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *NameTx) BaseEntryCost() uint64 {
|
||||||
|
return BaseEntryCost(tx.Name, tx.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *NameTx) String() string {
|
func (tx *NameTx) String() string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user