Skip to content
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

when reorg, it need unwind state fist #38

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common/block/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ type Log struct {
BlockNumber *uint256.Int `json:"blockNumber"`
// hash of the transaction
TxHash types.Hash `json:"transactionHash" gencodec:"required"`

// Address of the transaction
TxAddress types.Address `json:"-"`

// index of the transaction in the block
TxIndex uint `json:"transactionIndex" gencodec:"required"`
// hash of the block in which the transaction was included
Expand Down
55 changes: 55 additions & 0 deletions common/block/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ package block

import (
"bytes"
"errors"
"fmt"
"github.com/amazechain/amc/api/protocol/types_pb"
"github.com/amazechain/amc/common/crypto"
"github.com/amazechain/amc/common/transaction"
"github.com/amazechain/amc/common/types"
"github.com/amazechain/amc/internal/avm/rlp"
"github.com/amazechain/amc/params"
"github.com/amazechain/amc/utils"
"github.com/golang/protobuf/proto"
"github.com/holiman/uint256"
"math/big"
)

const (
Expand Down Expand Up @@ -96,6 +101,56 @@ func (rs *Receipts) ToProtoMessage() proto.Message {
}
}

// DeriveFields fills the receipts with their computed fields based on consensus
// data and contextual infos like containing block and transactions.
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash types.Hash, number uint64, txs []*transaction.Transaction) error {
signer := transaction.MakeSigner(config, new(big.Int).SetUint64(number))

logIndex := uint(0)
if len(txs) != len(rs) {
return errors.New("transaction and receipt count mismatch")
}
for i := 0; i < len(rs); i++ {
// The transaction type and hash can be retrieved from the transaction itself
rs[i].Type = txs[i].Type()
rs[i].TxHash = txs[i].Hash()

//rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee)

// block location fields
rs[i].BlockHash = hash
rs[i].BlockNumber = new(uint256.Int).SetUint64(number)
rs[i].TransactionIndex = uint(i)

// The contract address can be derived from the transaction itself
if txs[i].To() == nil {
// Deriving the signer is expensive, only do if it's actually needed
from, _ := transaction.Sender(signer, txs[i])
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
} else {
rs[i].ContractAddress = types.Address{}
}

// The used gas can be calculated based on previous r
if i == 0 {
rs[i].GasUsed = rs[i].CumulativeGasUsed
} else {
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
}

// The derived log fields can simply be set from the block and transaction
for j := 0; j < len(rs[i].Logs); j++ {
rs[i].Logs[j].BlockNumber = uint256.NewInt(number)
rs[i].Logs[j].BlockHash = hash
rs[i].Logs[j].TxHash = rs[i].TxHash
rs[i].Logs[j].TxIndex = uint(i)
rs[i].Logs[j].Index = logIndex
logIndex++
}
}
return nil
}

type Receipt struct {
// Consensus fields: These fields are defined by the Yellow Paper
Type uint8 `json:"type,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions common/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type IBlockChain interface {

GetDepositInfo(address types.Address) (*uint256.Int, *uint256.Int)
GetAccountRewardUnpaid(account types.Address) (*uint256.Int, error)
RewardsOfEpoch(number *uint256.Int, lastEpoch *uint256.Int) (map[types.Address]*uint256.Int, error)
}

type IMiner interface {
Expand Down
4 changes: 4 additions & 0 deletions common/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ type ChainHighestBlock struct {
type MinedEntireEvent struct {
Entire state.EntireCode
}

type ChainSideEvent struct {
Block *block.Block
}
1 change: 1 addition & 0 deletions conf/genesis_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

type GenesisBlockConfig struct {
Config *params.ChainConfig `json:"config" yaml:"config"`

// ChainID uint64 `json:"chainID" yaml:"chainID"`
Nonce uint64 `json:"nonce"`
Timestamp uint64 `json:"timestamp"`
Expand Down
149 changes: 103 additions & 46 deletions contracts/deposit/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import (
"bytes"
"context"
"embed"
"errors"
"github.com/amazechain/amc/common"
"github.com/amazechain/amc/common/crypto"
"github.com/amazechain/amc/common/crypto/bls"
"github.com/amazechain/amc/common/hexutil"
"github.com/amazechain/amc/common/transaction"
"github.com/amazechain/amc/common/types"
"github.com/amazechain/amc/conf"
"github.com/amazechain/amc/log"
Expand Down Expand Up @@ -92,7 +92,7 @@ func GetDepositInfo(tx kv.Tx, addr types.Address) *Info {
rewardPerBlock = new(uint256.Int).Add(rewardPerBlock, uint256.NewInt(params.Wei))
//
maxRewardPerEpoch = new(uint256.Int).Mul(rewardPerBlock, uint256.NewInt(FiveHundredDepositMaxTaskPerEpoch))
case 10: //todo
case 10, 0: //todo
return nil
default:
panic("wrong deposit amount")
Expand Down Expand Up @@ -178,15 +178,22 @@ func (d Deposit) eventLoop() {
if nil != d.consensusConfig.APos && bytes.Compare(l.Address[:], depositContractByes[:]) == 0 {
log.Trace("log event topic[0]= ", "hash", l.Topics[0], "depositEventSignature", depositEventSignature, "withdrawnSignature", withdrawnSignature)
if l.Topics[0] == depositEventSignature {
d.handleDepositEvent(l.TxHash, l.Data)
d.handleDepositEvent(l.TxHash, l.TxAddress, l.Data)
} else if l.Topics[0] == withdrawnSignature {
d.handleWithdrawnEvent(l.TxHash, l.Data)
d.handleWithdrawnEvent(l.TxHash, l.TxAddress, l.Data)
}
}
}
case logRemovedEvent := <-d.rmLogsCh:
for _, l := range logRemovedEvent.Logs {
log.Info("logEvent", "address", l.Address, "data", l.Data, "")
if nil != d.consensusConfig.APos && bytes.Compare(l.Address[:], depositContractByes[:]) == 0 {
log.Trace("log event topic[0]= ", "hash", l.Topics[0], "depositEventSignature", depositEventSignature, "withdrawnSignature", withdrawnSignature)
if l.Topics[0] == depositEventSignature {
d.handleUndoDepositEvent(l.TxHash, l.TxAddress, l.Data)
} else if l.Topics[0] == withdrawnSignature {
d.handleUndoWithdrawnEvent(l.TxHash, l.TxAddress, l.Data)
}
}
}
case <-d.logsSub.Err():
return
Expand All @@ -198,78 +205,128 @@ func (d Deposit) eventLoop() {
}
}

func (d Deposit) handleDepositEvent(txHash types.Hash, data []byte) {
func (d Deposit) verifySignature(sig []byte, pub []byte, depositAmount *uint256.Int) error {
// 1
signature, err := bls.SignatureFromBytes(sig)
if err != nil {
log.Warn("cannot unpack BLS signature", "signature", hexutil.Encode(sig), "err", err)
return err
}
// 2
publicKey, err := bls.PublicKeyFromBytes(pub)
if err != nil {
log.Warn("cannot unpack BLS publicKey", "publicKey", hexutil.Encode(pub), "err", err)
return err
}
// 3
log.Trace("DepositEvent verify:", "signature", hexutil.Encode(signature.Marshal()), "publicKey", hexutil.Encode(publicKey.Marshal()), "msg", hexutil.Encode(depositAmount.Bytes()))
if !signature.Verify(publicKey, depositAmount.Bytes()) {
return errors.New("cannot Verify signature")
}

return nil
}

func (d Deposit) handleDepositEvent(txHash types.Hash, txAddress types.Address, data []byte) {

pb, amount, sig, err := UnpackDepositLogData(data)
if err != nil {
log.Warn("cannot unpack deposit log data")
return
}
// 2
signature, err := bls.SignatureFromBytes(sig)

if err := d.verifySignature(sig, pb, amount); err != nil {
log.Error("cannot Verify signature", "signature", hexutil.Encode(sig), "publicKey", hexutil.Encode(pb), "message", hexutil.Encode(amount.Bytes()), "err", err)
return
}

rwTx, err := d.db.BeginRw(d.ctx)
defer rwTx.Rollback()
if err != nil {
log.Warn("cannot unpack BLS signature", "signature", hexutil.Encode(sig), "err", err)
log.Error("cannot open db", "err", err)
return
}
// 3
publicKey, err := bls.PublicKeyFromBytes(pb)

var pub types.PublicKey
_ = pub.SetBytes(pb)
//
if err = rawdb.DoDeposit(rwTx, txAddress, pub, amount); err != nil {
log.Error("cannot modify database", "err", err)
}
if err = rwTx.Commit(); err != nil {
log.Error("cannot commit tx", "err", err)
}
}

func (d Deposit) handleUndoDepositEvent(txHash types.Hash, txAddress types.Address, data []byte) {
pb, amount, sig, err := UnpackDepositLogData(data)
if err != nil {
log.Warn("cannot unpack BLS publicKey", "publicKey", hexutil.Encode(pb), "err", err)
log.Warn("cannot unpack deposit log data")
return
}
// 4
log.Trace("DepositEvent verify:", "signature", hexutil.Encode(signature.Marshal()), "publicKey", hexutil.Encode(publicKey.Marshal()), "msg", hexutil.Encode(amount.Bytes()))
if signature.Verify(publicKey, amount.Bytes()) {
var tx *transaction.Transaction
rwTx, err := d.db.BeginRw(d.ctx)
defer rwTx.Rollback()
if err != nil {
log.Error("cannot open db", "err", err)
return
}

tx, _, _, _, err = rawdb.ReadTransactionByHash(rwTx, txHash)
if err != nil {
log.Error("rawdb.ReadTransactionByHash", "err", err, "hash", txHash)
}
if err := d.verifySignature(sig, pb, amount); err != nil {
log.Error("cannot Verify signature", "signature", hexutil.Encode(sig), "publicKey", hexutil.Encode(pb), "message", hexutil.Encode(amount.Bytes()), "err", err)
return
}

if tx != nil {
log.Trace("add Deposit info", "address", tx.From(), "amount", amount.String())
rwTx, err := d.db.BeginRw(d.ctx)
defer rwTx.Rollback()
if err != nil {
log.Error("cannot open db", "err", err)
return
}

var pub types.PublicKey
pub.SetBytes(publicKey.Marshal())
//
rawdb.PutDeposit(rwTx, *tx.From(), pub, *amount)
rwTx.Commit()
}
} else {
log.Error("DepositEvent cannot Verify signature", "signature", hexutil.Encode(sig), "publicKey", hexutil.Encode(pb), "message", hexutil.Encode(amount.Bytes()), "err", err)
//
if err = rawdb.UndoDeposit(rwTx, txAddress, amount); err != nil {
log.Error("cannot modify database", "err", err)
}
if err = rwTx.Commit(); err != nil {
log.Error("cannot commit tx", "err", err)
}

}

func (d Deposit) handleWithdrawnEvent(txHash types.Hash, data []byte) {
var tx *transaction.Transaction
func (d Deposit) handleWithdrawnEvent(txHash types.Hash, txAddress types.Address, data []byte) {
// 1
amount, err := UnpackWithdrawnLogData(data)
if err != nil {
log.Warn("cannot unpack deposit log data")
return
}

rwTx, err := d.db.BeginRw(d.ctx)
defer rwTx.Rollback()
if err != nil {
log.Error("cannot open db", "err", err)
return
}
tx, _, _, _, err = rawdb.ReadTransactionByHash(rwTx, txHash)

err = rawdb.DoWithdrawn(rwTx, txAddress, amount)
if err != nil {
log.Error("rawdb.ReadTransactionByHash", "err", err, "hash", txHash)
log.Error("cannot Withdrawn deposit when handle Withdrawn Event", "err", err)
return
}
if tx == nil {
log.Error("cannot find Transaction", "err", err, "hash", txHash)
return
if err = rwTx.Commit(); nil != err {
log.Error("cannot commit when handle Withdrawn Event", "err", err)
}
}

err = rawdb.DeleteDeposit(rwTx, *tx.From())
func (d Deposit) handleUndoWithdrawnEvent(txHash types.Hash, txAddress types.Address, data []byte) {
amount, err := UnpackWithdrawnLogData(data)
if err != nil {
log.Error("cannot delete deposit", "err", err)
log.Warn("cannot unpack deposit log data")
return
}
rwTx, err := d.db.BeginRw(d.ctx)
defer rwTx.Rollback()

if err = rawdb.UndoWithdrawn(rwTx, txAddress, amount); err != nil {
log.Error("cannot Undo Withdrawn deposit when handle remove Withdrawn log Event", "err", err)
return
}
rwTx.Commit()

if err = rwTx.Commit(); nil != err {
log.Error("cannot commit when handle Withdrawn Event", "err", err)
}
}
22 changes: 22 additions & 0 deletions contracts/deposit/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,25 @@ func UnpackDepositLogData(data []byte) (pubkey []byte, amount *uint256.Int, sign

return unpackedLogs[0].([]byte), amount, unpackedLogs[2].([]byte), nil
}

// UnpackWithdrawnLogData unpacks the data from a deposit log using the ABI decoder.
func UnpackWithdrawnLogData(data []byte) (amount *uint256.Int, err error) {
reader := bytes.NewReader(depositAbiCode)
contractAbi, err := abi.JSON(reader)
if err != nil {
return nil, errors.Wrap(err, "unable to generate contract abi")
}

unpackedLogs, err := contractAbi.Unpack("WithdrawnEvent", data)
if err != nil {
return nil, errors.Wrap(err, "unable to unpack logs")
}
amount, overflow := uint256.FromBig(unpackedLogs[0].(*big.Int))
if overflow {
return nil, errors.New("unable to unpack amount")
}

log.Debug("unpacked WithdrawnEvent Logs", "message", hexutil.Encode(amount.Bytes()))

return amount, nil
}
Loading