fix cross shard tx nonce issue

pull/1357/head
chao 5 years ago
parent db56a7b7c2
commit e87820d593
  1. 8
      api/proto/node/node.go
  2. 2
      cmd/client/wallet/main.go
  3. 35
      core/state_processor.go
  4. 4
      core/state_transition.go
  5. 17
      core/types/block.go
  6. 9
      core/types/cx_receipt.go
  7. 3
      core/types/derive_sha.go
  8. 6
      core/types/transaction.go
  9. 6
      node/node_cross_shard.go
  10. 7
      node/worker/worker.go

@ -37,8 +37,8 @@ type BlockchainSyncMessage struct {
// CXReceiptsMessage carrys the cross shard receipts and merkle proof
type CXReceiptsMessage struct {
CXS types.CXReceipts
MKP *types.CXMerkleProof
Receipts types.CXReceipts
MerkleProof *types.CXMerkleProof
}
// BlockchainSyncMessageType represents BlockchainSyncMessageType type.
@ -197,7 +197,7 @@ func DeserializeEpochShardStateFromMessage(payload []byte) (*types.EpochShardSta
// ConstructCXReceiptsMessage constructs cross shard receipts and merkle proof
func ConstructCXReceiptsMessage(cxs types.CXReceipts, mkp *types.CXMerkleProof) []byte {
msg := &CXReceiptsMessage{CXS: cxs, MKP: mkp}
msg := &CXReceiptsMessage{Receipts: cxs, MerkleProof: mkp}
byteBuffer := bytes.NewBuffer([]byte{byte(proto.Node)})
byteBuffer.WriteByte(byte(Block))
@ -205,7 +205,7 @@ func ConstructCXReceiptsMessage(cxs types.CXReceipts, mkp *types.CXMerkleProof)
by, err := rlp.EncodeToBytes(msg)
if err != nil {
log.Fatal(err)
utils.Logger().Error().Err(err).Msg("[ConstructCXReceiptsMessage] Encode CXReceiptsMessage Error")
return []byte{}
}
byteBuffer.Write(by)

@ -92,7 +92,7 @@ var (
transferReceiverPtr = transferCommand.String("to", "", "Specify the receiver account")
transferAmountPtr = transferCommand.Float64("amount", 0, "Specify the amount to transfer")
transferShardIDPtr = transferCommand.Int("shardID", 0, "Specify the shard ID for the transfer")
transferToShardIDPtr = transferCommand.Int("toShardID", 0, "Specify the shard ID for the transfer")
transferToShardIDPtr = transferCommand.Int("toShardID", 0, "Specify the destination shard ID for the transfer")
transferInputDataPtr = transferCommand.String("inputData", "", "Base64-encoded input data to embed in the transaction")
transferSenderPassPtr = transferCommand.String("pass", "", "Passphrase of the sender's private key")

@ -17,6 +17,8 @@
package core
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
@ -71,7 +73,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C
return nil, nil, nil, 0, err
}
receipts = append(receipts, receipt)
cxs = append(cxs, cxReceipt)
if cxReceipt != nil {
cxs = append(cxs, cxReceipt)
}
allLogs = append(allLogs, receipt.Logs...)
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
@ -83,11 +87,33 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C
return receipts, cxs, allLogs, *usedGas, nil
}
// return true if it is valid
func verifyTransactionType(header *types.Header, tx *types.Transaction) error {
switch tx.TxType() {
case types.SameShardTx:
if tx.ShardID() == tx.ToShardID() && header.ShardID == tx.ShardID() {
return nil
}
case types.SubtractionOnly:
if tx.ShardID() != tx.ToShardID() && header.ShardID == tx.ShardID() {
return nil
}
case types.AdditionOnly:
if tx.ShardID() != tx.ToShardID() && header.ShardID == tx.ToShardID() {
return nil
}
}
return fmt.Errorf("Invalid Transaction Type: %v", tx.TxType())
}
// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.DB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, *types.CXReceipt, uint64, error) {
if err := verifyTransactionType(header, tx); err != nil {
return nil, nil, 0, err
}
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
// skip signer err for additiononly tx
if err != nil && msg.TxType() != types.AdditionOnly {
@ -126,7 +152,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
//receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
cxReceipt := &types.CXReceipt{tx.Hash(), msg.Nonce(), msg.From(), msg.To(), tx.ShardID(), tx.ToShardID(), msg.Value()}
var cxReceipt *types.CXReceipt
if tx.TxType() == types.SubtractionOnly {
cxReceipt = &types.CXReceipt{tx.Hash(), msg.Nonce(), msg.From(), msg.To(), tx.ShardID(), tx.ToShardID(), msg.Value()}
} else {
cxReceipt = nil
}
return receipt, cxReceipt, gas, err
}

@ -215,7 +215,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
} else {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
if st.txType != types.AdditionOnly {
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
}
ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value, st.txType)
}
if vmerr != nil {

@ -76,14 +76,15 @@ type Header struct {
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
CXReceiptHash common.Hash `json:"cxReceiptsRoot" gencodec:"required"`
Bloom ethtypes.Bloom `json:"logsBloom" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
CXReceiptHash common.Hash `json:"outgoingReceiptsRoot" gencodec:"required"`
//IncomingReceiptHash common.Hash `json:"incomingReceiptsRoot" gencodec:"required"`
Bloom ethtypes.Bloom `json:"logsBloom" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
// Additional Fields
ViewID *big.Int `json:"viewID" gencodec:"required"`
Epoch *big.Int `json:"epoch" gencodec:"required"`

@ -29,18 +29,27 @@ func (cs CXReceipts) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }
// GetRlp implements Rlpable and returns the i'th element of s in rlp.
func (cs CXReceipts) GetRlp(i int) []byte {
if len(cs) == 0 {
return []byte{}
}
enc, _ := rlp.EncodeToBytes(cs[i])
return enc
}
// ToShardID returns the destination shardID of the cxReceipt
func (cs CXReceipts) ToShardID(i int) uint32 {
if len(cs) == 0 {
return 0
}
return cs[i].ToShardID
}
// MaxToShardID returns the maximum destination shardID of cxReceipts
func (cs CXReceipts) MaxToShardID() uint32 {
maxShardID := uint32(0)
if len(cs) == 0 {
return maxShardID
}
for i := 0; i < len(cs); i++ {
if maxShardID < cs[i].ToShardID {
maxShardID = cs[i].ToShardID

@ -67,6 +67,9 @@ func DeriveOneShardSha(list DerivableList, shardID uint32) common.Hash {
// else, return |shard0|trieHash0|shard1|trieHash1|...| for non-empty destination shards
func DeriveMultipleShardsSha(list DerivableList) common.Hash {
by := []byte{}
if list.Len() == 0 {
return EmptyRootHash
}
for i := 0; i <= int(list.MaxToShardID()); i++ {
shardHash := DeriveOneShardSha(list, uint32(i))
if shardHash == EmptyRootHash {

@ -76,8 +76,7 @@ type txdata struct {
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value" gencodec:"required"`
Payload []byte `json:"input" gencodec:"required"`
TxType TransactionType `json:"transactionType" gencodec:"required"`
TxType TransactionType
// Signature values
V *big.Int `json:"v" gencodec:"required"`
@ -107,6 +106,9 @@ func NewTransaction(nonce uint64, to common.Address, shardID uint32, amount *big
// NewCrossShardTransaction returns new cross shard transaction
func NewCrossShardTransaction(nonce uint64, to *common.Address, shardID uint32, toShardID uint32, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, txType TransactionType) *Transaction {
if shardID == toShardID {
return newTransaction(nonce, to, shardID, amount, gasLimit, gasPrice, data)
}
return newCrossShardTransaction(nonce, to, shardID, toShardID, amount, gasLimit, gasPrice, data, txType)
}

@ -35,7 +35,7 @@ func (node *Node) ProcessReceiptMessage(msgPayload []byte) {
utils.Logger().Error().Err(err).Msg("[ProcessReceiptMessage] Unable to Decode message Payload")
return
}
merkleProof := cxmsg.MKP
merkleProof := cxmsg.MerkleProof
myShardRoot := common.Hash{}
var foundMyShard bool
@ -65,7 +65,7 @@ func (node *Node) ProcessReceiptMessage(msgPayload []byte) {
utils.Logger().Debug().Interface("hash", hash).Msg("[ProcessReceiptMessage] RootHash of the CXReceipts")
// TODO chao: use crosslink from beacon sync to verify the hash
cxReceipts := cxmsg.CXS
cxReceipts := cxmsg.Receipts
sha := types.DeriveSha(cxReceipts)
if sha != myShardRoot {
utils.Logger().Warn().Interface("calculated", sha).Interface("got", myShardRoot).Msg("[ProcessReceiptMessage] Trie Root of CXReceipts Not Match")
@ -81,7 +81,7 @@ func (node *Node) ProcessReceiptMessage(msgPayload []byte) {
}
for _, cx := range cxReceipts {
// TODO chao: add gas fee to incentivize
tx := types.NewCrossShardTransaction(0, cx.To, cx.ToShardID, cx.ToShardID, cx.Amount, gas, nil, inputData, types.AdditionOnly)
tx := types.NewCrossShardTransaction(0, cx.To, cx.ShardID, cx.ToShardID, cx.Amount, gas, nil, inputData, types.AdditionOnly)
txs = append(txs, tx)
}
node.addPendingTransactions(txs)

@ -52,8 +52,9 @@ func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, maxNumTxs
unselected := types.Transactions{}
invalid := types.Transactions{}
for _, tx := range txs {
if tx.ShardID() != w.shardID {
if tx.ShardID() != w.shardID && tx.ToShardID() != w.shardID {
invalid = append(invalid, tx)
continue
}
snap := w.current.state.Snapshot()
_, err := w.commitTransaction(tx, coinbase)
@ -86,7 +87,9 @@ func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
}
w.current.txs = append(w.current.txs, tx)
w.current.receipts = append(w.current.receipts, receipt)
w.current.cxs = append(w.current.cxs, cx)
if cx != nil {
w.current.cxs = append(w.current.cxs, cx)
}
return receipt.Logs, nil
}

Loading…
Cancel
Save