Skip to content

Commit

Permalink
Refactor: ETXs use txhash/index, no longer have any fees or nonce, an…
Browse files Browse the repository at this point in the history
…d inbound are added to block first

Address location fixes and json unmarshal fixes
  • Loading branch information
jdowning100 committed Feb 16, 2024
1 parent c128e16 commit 13f3b95
Show file tree
Hide file tree
Showing 28 changed files with 400 additions and 317 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ debug:
go-quai:
$(GORUN) build/ci.go build ./cmd/go-quai
@echo "Done building."
@echo "Run \"$(GOBIN)/go-quai\" to launch go-quai."
@echo "Run \"$(GOBIN)/go-quai\" to launch go-quai."
19 changes: 16 additions & 3 deletions common/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type AddressData interface {
UnmarshalJSON(input []byte) error
Scan(src interface{}) error
Value() (driver.Value, error)
Location(nodeLocation Location) *Location
Location() *Location
setBytes(b []byte)
}

Expand Down Expand Up @@ -213,11 +213,11 @@ func (a Address) Value() (driver.Value, error) {
}

// Location looks up the chain location which contains this address
func (a Address) Location(nodeLocation Location) *Location {
func (a Address) Location() *Location {
if a.inner == nil {
panic("Address has nil inner")
}
return a.inner.Location(nodeLocation)
return a.inner.Location()
}

// BigToAddress returns Address with byte values of b.
Expand All @@ -241,6 +241,19 @@ func IsHexAddress(s string) bool {
return len(s) == 2*AddressLength && isHex(s)
}

func (a *AddressBytes) UnmarshalJSON(input []byte) error {
var temp [AddressLength]byte
if err := hexutil.UnmarshalFixedJSON(reflect.TypeOf(AddressBytes{}), input, temp[:]); err != nil {
return err
}
copy(a[:], temp[:])
return nil
}

func (a AddressBytes) MarshalJSON() ([]byte, error) {
return json.Marshal(a[:])
}

// Hex returns a hex string representation of the address.
func (a AddressBytes) Hex() string {
return string(a.checksumHex())
Expand Down
44 changes: 5 additions & 39 deletions common/external_address.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,43 +127,9 @@ func (a ExternalAddress) Value() (driver.Value, error) {
return a[:], nil
}

// Location looks up the chain location which contains this address
func (a ExternalAddress) Location(nodeLocation Location) *Location {
R, Z, D := 0, 0, HierarchyDepth
if nodeLocation.HasRegion() {
R = nodeLocation.Region()
}
if nodeLocation.HasZone() {
Z = nodeLocation.Zone()
}

// Search zone->region->prime address spaces in-slice first, and then search
// zone->region out-of-slice address spaces next. This minimizes expected
// search time under the following assumptions:
// * a node is more likely to encounter a TX from its slice than from another
// * we expect `>= Z` `zone` TXs for every `region` TX
// * we expect `>= R` `region` TXs for every `prime` TX
// * (and by extension) we expect `>= R*Z` `zone` TXs for every `prime` TX
primeChecked := false
for r := 0; r < NumRegionsInPrime; r++ {
for z := 0; z < NumZonesInRegion; z++ {
l := Location{byte((r + R) % D), byte((z + Z) % D)}
if l.ContainsAddress(Address{&a}) {
return &l
}
}
l := Location{byte((r + R) % D)}
if l.ContainsAddress(Address{&a}) {
return &l
}
// Check prime on first pass through slice, but not again
if !primeChecked {
primeChecked = true
l := Location{}
if l.ContainsAddress(Address{&a}) {
return &l
}
}
}
return nil
func (a ExternalAddress) Location() *Location {
// Extract nibbles
lowerNib := a[0] & 0x0F // Lower 4 bits
upperNib := (a[0] & 0xF0) >> 4 // Upper 4 bits, shifted right
return &Location{upperNib, lowerNib}
}
7 changes: 5 additions & 2 deletions common/internal_address.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ func (a InternalAddress) Value() (driver.Value, error) {
return a[:], nil
}

func (a InternalAddress) Location(nodeLocation Location) *Location {
return &nodeLocation
func (a InternalAddress) Location() *Location {
// Extract nibbles
lowerNib := a[0] & 0x0F // Lower 4 bits
upperNib := (a[0] & 0xF0) >> 4 // Upper 4 bits, shifted right
return &Location{upperNib, lowerNib}
}
4 changes: 2 additions & 2 deletions common/proto_common.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ func (c *Core) AddRemote(tx *types.Transaction) error {
}

func (c *Core) TxPoolPending(enforceTips bool) (map[common.AddressBytes]types.Transactions, error) {
return c.sl.txPool.TxPoolPending(enforceTips, nil)
return c.sl.txPool.TxPoolPending(enforceTips)
}

func (c *Core) Get(hash common.Hash) *types.Transaction {
Expand Down
1 change: 1 addition & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func NewEVMTxContext(msg Message) vm.TxContext {
GasPrice: new(big.Int).Set(msg.GasPrice()),
ETXSender: msg.ETXSender(),
TxType: msg.Type(),
Hash: msg.Hash(),
ETXGasLimit: msg.ETXGasLimit(),
ETXGasPrice: msg.ETXGasPrice(),
ETXGasTip: msg.ETXGasTip(),
Expand Down
2 changes: 1 addition & 1 deletion core/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.Block, location common.L
}

// Filter for ETXs destined to this slice
newInboundEtxs := subRollup.FilterToSlice(location, nodeCtx, nodeLocation)
newInboundEtxs := subRollup.FilterToSlice(location, nodeCtx)

// Filter this list to exclude any ETX for which we are not the crossing
// context node. Such ETXs cannot be used by our subordinate for one of the
Expand Down
4 changes: 2 additions & 2 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,11 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
var ETXPCount int
for _, tx := range result.Etxs {
// Count which ETXs are cross-region
if tx.To().Location(nodeLocation).CommonDom(nodeLocation).Context() == common.REGION_CTX {
if tx.To().Location().CommonDom(nodeLocation).Context() == common.REGION_CTX {
ETXRCount++
}
// Count which ETXs are cross-prime
if tx.To().Location(nodeLocation).CommonDom(nodeLocation).Context() == common.PRIME_CTX {
if tx.To().Location().CommonDom(nodeLocation).Context() == common.PRIME_CTX {
ETXPCount++
}
}
Expand Down
40 changes: 28 additions & 12 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,12 @@ type Message interface {
Value() *big.Int

Nonce() uint64
CheckNonce() bool
IsETX() bool
Data() []byte
AccessList() types.AccessList
ETXSender() common.Address
Type() byte
Hash() common.Hash

ETXGasLimit() uint64
ETXGasPrice() *big.Int
Expand Down Expand Up @@ -223,21 +224,31 @@ func (st *StateTransition) buyGas() error {
return nil
}

// subGasETX subtracts the gas for an ETX from the gas pool and adds it to the total gas used.
// The ETX does not pay for the gas.
func (st *StateTransition) subGasETX() error {
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
return err
}
st.gas += st.msg.Gas()

st.initialGas = st.msg.Gas()
return nil
}

func (st *StateTransition) preCheck() error {
from, err := st.msg.From().InternalAddress()
if err != nil {
return err
}
// Make sure this transaction's nonce is correct.
if st.msg.CheckNonce() {
stNonce := st.state.GetNonce(from)
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
st.msg.From().Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
st.msg.From().Hex(), msgNonce, stNonce)
}
stNonce := st.state.GetNonce(from)
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
st.msg.From().Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
st.msg.From().Hex(), msgNonce, stNonce)
}
// Make sure the sender is an EOA
if codeHash := st.state.GetCodeHash(from); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
Expand Down Expand Up @@ -294,9 +305,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// 6. caller has enough balance to cover asset transfer for **topmost** call

// Check clauses 1-3, buy gas if everything is correct
if err := st.preCheck(); err != nil {
if !st.msg.IsETX() {
if err := st.preCheck(); err != nil {
return nil, err
}
} else if err := st.subGasETX(); err != nil {
return nil, err
}

msg := st.msg
sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil // for ETX contract creation, perhaps we should compare the "to" to the contextual zero-address (only in the ETX case)
Expand Down Expand Up @@ -355,7 +371,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
if err != nil {
return nil, err
}
st.state.AddBalance(coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
st.state.AddBalance(coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) // todo: etxs no longer pay the miner a fee

return &ExecutionResult{
UsedGas: st.gasUsed(),
Expand Down
25 changes: 1 addition & 24 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ func (pool *TxPool) ContentFrom(addr common.InternalAddress) (types.Transactions
// The enforceTips parameter can be used to do an extra filtering on the pending
// transactions and only return those whose **effective** tip is large enough in
// the next pending execution environment.
func (pool *TxPool) TxPoolPending(enforceTips bool, etxSet types.EtxSet) (map[common.AddressBytes]types.Transactions, error) {
func (pool *TxPool) TxPoolPending(enforceTips bool) (map[common.AddressBytes]types.Transactions, error) {
pool.mu.RLock()
defer pool.mu.RUnlock()

Expand All @@ -625,29 +625,6 @@ func (pool *TxPool) TxPoolPending(enforceTips bool, etxSet types.EtxSet) (map[co
pending[addr.Bytes20()] = txs
}
}

for _, entry := range etxSet {
addr := entry.ETX.ETXSender()
tx := entry.ETX
if tx.ETXSender().Location(pool.chainconfig.Location).Equal(pool.chainconfig.Location) { // Sanity check
pool.logger.WithFields(log.Fields{
"tx": tx.Hash().String(),
"sender": tx.ETXSender().String(),
}).Error("ETX sender is in our location!")
continue // skip this tx
}
// If the miner requests tip enforcement, cap the lists now
if enforceTips && tx.EffectiveGasTipIntCmp(pool.gasPrice, pool.priced.urgent.baseFee) < 0 {
pool.logger.WithFields(log.Fields{
"tx": tx.Hash().String(),
"gasTipCap": tx.GasTipCap().String(),
"poolGasPrice": pool.gasPrice.String(),
"baseFee": pool.priced.urgent.baseFee.String(),
}).Debug("ETX has incorrect or low miner tip")
continue // skip this tx
}
pending[addr.Bytes20()] = append(pending[addr.Bytes20()], &tx) // ETXs do not have to be sorted by address but this way all TXs are in the same list
}
return pending, nil
}

Expand Down
2 changes: 1 addition & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
}
h.parentHash = eh.ParentHash
h.uncleHash = eh.UncleHash
h.coinbase = eh.Coinbase
h.coinbase = common.BytesToAddress(eh.Coinbase.Bytes(), eh.Location)
h.root = eh.Root
h.txHash = eh.TxHash
h.etxHash = eh.EtxHash
Expand Down
2 changes: 1 addition & 1 deletion core/types/etx_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewEtxSet() EtxSet {
func (set *EtxSet) Update(newInboundEtxs Transactions, currentHeight uint64, nodeLocation common.Location) {
// Add new ETX entries to the inbound set
for _, etx := range newInboundEtxs {
if etx.To().Location(nodeLocation).Equal(nodeLocation) {
if etx.To().Location().Equal(nodeLocation) {
(*set)[etx.Hash()] = EtxSetEntry{currentHeight, *etx}
} else {
panic("cannot add ETX destined to other chain to our ETX set")
Expand Down
Loading

0 comments on commit 13f3b95

Please sign in to comment.