github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/state/converters.go (about)

     1  package state
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"time"
     8  
     9  	"github.com/0xPolygon/supernets2-node/encoding"
    10  	"github.com/0xPolygon/supernets2-node/event"
    11  	"github.com/0xPolygon/supernets2-node/hex"
    12  	"github.com/0xPolygon/supernets2-node/log"
    13  	"github.com/0xPolygon/supernets2-node/state/runtime/executor"
    14  	"github.com/0xPolygon/supernets2-node/state/runtime/executor/pb"
    15  	"github.com/0xPolygon/supernets2-node/state/runtime/fakevm"
    16  	"github.com/0xPolygon/supernets2-node/state/runtime/instrumentation"
    17  	"github.com/ethereum/go-ethereum/common"
    18  	"github.com/ethereum/go-ethereum/core/types"
    19  )
    20  
    21  // ConvertToCounters extracts ZKCounters from a ProcessBatchResponse
    22  func ConvertToCounters(resp *pb.ProcessBatchResponse) ZKCounters {
    23  	return ZKCounters{
    24  		CumulativeGasUsed:    resp.CumulativeGasUsed,
    25  		UsedKeccakHashes:     resp.CntKeccakHashes,
    26  		UsedPoseidonHashes:   resp.CntPoseidonHashes,
    27  		UsedPoseidonPaddings: resp.CntPoseidonPaddings,
    28  		UsedMemAligns:        resp.CntMemAligns,
    29  		UsedArithmetics:      resp.CntArithmetics,
    30  		UsedBinaries:         resp.CntBinaries,
    31  		UsedSteps:            resp.CntSteps,
    32  	}
    33  }
    34  
    35  // TestConvertToProcessBatchResponse for test purposes
    36  func (s *State) TestConvertToProcessBatchResponse(txs []types.Transaction, response *pb.ProcessBatchResponse) (*ProcessBatchResponse, error) {
    37  	return s.convertToProcessBatchResponse(txs, response)
    38  }
    39  
    40  func (s *State) convertToProcessBatchResponse(txs []types.Transaction, response *pb.ProcessBatchResponse) (*ProcessBatchResponse, error) {
    41  	responses, err := s.convertToProcessTransactionResponse(txs, response.Responses)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	readWriteAddresses, err := convertToReadWriteAddresses(response.ReadWriteAddresses)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	isExecutorLevelError := (response.Error != executor.EXECUTOR_ERROR_NO_ERROR)
    52  	isRomLevelError := false
    53  	isRomOOCError := false
    54  
    55  	if response.Responses != nil {
    56  		for _, resp := range response.Responses {
    57  			if resp.Error != pb.RomError_ROM_ERROR_NO_ERROR {
    58  				isRomLevelError = true
    59  				break
    60  			}
    61  		}
    62  
    63  		if len(response.Responses) > 0 {
    64  			// Check out of counters
    65  			errorToCheck := response.Responses[len(response.Responses)-1].Error
    66  			isRomOOCError = executor.IsROMOutOfCountersError(errorToCheck)
    67  		}
    68  	}
    69  
    70  	return &ProcessBatchResponse{
    71  		NewStateRoot:         common.BytesToHash(response.NewStateRoot),
    72  		NewAccInputHash:      common.BytesToHash(response.NewAccInputHash),
    73  		NewLocalExitRoot:     common.BytesToHash(response.NewLocalExitRoot),
    74  		NewBatchNumber:       response.NewBatchNum,
    75  		UsedZkCounters:       convertToCounters(response),
    76  		Responses:            responses,
    77  		ExecutorError:        executor.ExecutorErr(response.Error),
    78  		IsExecutorLevelError: isExecutorLevelError,
    79  		IsRomLevelError:      isRomLevelError,
    80  		IsRomOOCError:        isRomOOCError,
    81  		ReadWriteAddresses:   readWriteAddresses,
    82  	}, nil
    83  }
    84  
    85  // IsStateRootChanged returns true if the transaction changes the state root
    86  func IsStateRootChanged(err pb.RomError) bool {
    87  	return !executor.IsIntrinsicError(err) && !executor.IsROMOutOfCountersError(err)
    88  }
    89  
    90  func convertToReadWriteAddresses(addresses map[string]*pb.InfoReadWrite) (map[common.Address]*InfoReadWrite, error) {
    91  	results := make(map[common.Address]*InfoReadWrite, len(addresses))
    92  
    93  	for addr, addrInfo := range addresses {
    94  		var nonce *uint64 = nil
    95  		var balance *big.Int = nil
    96  		var ok bool
    97  
    98  		address := common.HexToAddress(addr)
    99  
   100  		if addrInfo.Nonce != "" {
   101  			bigNonce, ok := new(big.Int).SetString(addrInfo.Nonce, encoding.Base10)
   102  			if !ok {
   103  				log.Debugf("received nonce as string: %v", addrInfo.Nonce)
   104  				return nil, fmt.Errorf("error while parsing address nonce")
   105  			}
   106  			nonceNp := bigNonce.Uint64()
   107  			nonce = &nonceNp
   108  		}
   109  
   110  		if addrInfo.Balance != "" {
   111  			balance, ok = new(big.Int).SetString(addrInfo.Balance, encoding.Base10)
   112  			if !ok {
   113  				log.Debugf("received balance as string: %v", addrInfo.Balance)
   114  				return nil, fmt.Errorf("error while parsing address balance")
   115  			}
   116  		}
   117  
   118  		results[address] = &InfoReadWrite{Address: address, Nonce: nonce, Balance: balance}
   119  	}
   120  
   121  	return results, nil
   122  }
   123  
   124  func (s *State) convertToProcessTransactionResponse(txs []types.Transaction, responses []*pb.ProcessTransactionResponse) ([]*ProcessTransactionResponse, error) {
   125  	results := make([]*ProcessTransactionResponse, 0, len(responses))
   126  	for i, response := range responses {
   127  		trace, err := convertToStructLogArray(response.ExecutionTrace)
   128  		if err != nil {
   129  			return nil, err
   130  		}
   131  
   132  		result := new(ProcessTransactionResponse)
   133  		result.TxHash = common.BytesToHash(response.TxHash)
   134  		result.Type = response.Type
   135  		result.ReturnValue = response.ReturnValue
   136  		result.GasLeft = response.GasLeft
   137  		result.GasUsed = response.GasUsed
   138  		result.GasRefunded = response.GasRefunded
   139  		result.RomError = executor.RomErr(response.Error)
   140  		result.CreateAddress = common.HexToAddress(response.CreateAddress)
   141  		result.StateRoot = common.BytesToHash(response.StateRoot)
   142  		result.Logs = convertToLog(response.Logs)
   143  		result.ChangesStateRoot = IsStateRootChanged(response.Error)
   144  		result.ExecutionTrace = *trace
   145  		result.CallTrace = convertToExecutorTrace(response.CallTrace)
   146  		result.Tx = txs[i]
   147  
   148  		_, err = DecodeTx(common.Bytes2Hex(response.GetRlpTx()))
   149  		if err != nil {
   150  			timestamp := time.Now()
   151  			log.Errorf("error decoding rlp returned by executor %v at %v", err, timestamp)
   152  
   153  			event := &event.Event{
   154  				ReceivedAt: timestamp,
   155  				Source:     event.Source_Node,
   156  				Level:      event.Level_Error,
   157  				EventID:    event.EventID_ExecutorRLPError,
   158  				Json:       string(response.GetRlpTx()),
   159  			}
   160  
   161  			err = s.eventLog.LogEvent(context.Background(), event)
   162  			if err != nil {
   163  				log.Errorf("error storing payload: %v", err)
   164  			}
   165  		}
   166  
   167  		results = append(results, result)
   168  
   169  		log.Debugf("ProcessTransactionResponse[TxHash]: %v", result.TxHash)
   170  		log.Debugf("ProcessTransactionResponse[Nonce]: %v", result.Tx.Nonce())
   171  		log.Debugf("ProcessTransactionResponse[StateRoot]: %v", result.StateRoot.String())
   172  		log.Debugf("ProcessTransactionResponse[Error]: %v", result.RomError)
   173  		log.Debugf("ProcessTransactionResponse[GasUsed]: %v", result.GasUsed)
   174  		log.Debugf("ProcessTransactionResponse[GasLeft]: %v", result.GasLeft)
   175  		log.Debugf("ProcessTransactionResponse[GasRefunded]: %v", result.GasRefunded)
   176  		log.Debugf("ProcessTransactionResponse[ChangesStateRoot]: %v", result.ChangesStateRoot)
   177  	}
   178  
   179  	return results, nil
   180  }
   181  
   182  func convertToLog(protoLogs []*pb.Log) []*types.Log {
   183  	logs := make([]*types.Log, 0, len(protoLogs))
   184  
   185  	for _, protoLog := range protoLogs {
   186  		log := new(types.Log)
   187  		log.Address = common.HexToAddress(protoLog.Address)
   188  		log.Topics = convertToTopics(protoLog.Topics)
   189  		log.Data = protoLog.Data
   190  		log.BlockNumber = protoLog.BatchNumber
   191  		log.TxHash = common.BytesToHash(protoLog.TxHash)
   192  		log.TxIndex = uint(protoLog.TxIndex)
   193  		log.BlockHash = common.BytesToHash(protoLog.BatchHash)
   194  		log.Index = uint(protoLog.Index)
   195  		logs = append(logs, log)
   196  	}
   197  
   198  	return logs
   199  }
   200  
   201  func convertToTopics(responses [][]byte) []common.Hash {
   202  	results := make([]common.Hash, 0, len(responses))
   203  
   204  	for _, response := range responses {
   205  		results = append(results, common.BytesToHash(response))
   206  	}
   207  	return results
   208  }
   209  
   210  func convertToStructLogArray(responses []*pb.ExecutionTraceStep) (*[]instrumentation.StructLog, error) {
   211  	results := make([]instrumentation.StructLog, 0, len(responses))
   212  
   213  	for _, response := range responses {
   214  		convertedStack, err := convertToBigIntArray(response.Stack)
   215  		if err != nil {
   216  			return nil, err
   217  		}
   218  		result := new(instrumentation.StructLog)
   219  		result.Pc = response.Pc
   220  		result.Op = response.Op
   221  		result.Gas = response.RemainingGas
   222  		result.GasCost = response.GasCost
   223  		result.Memory = response.Memory
   224  		result.MemorySize = int(response.MemorySize)
   225  		result.Stack = convertedStack
   226  		result.ReturnData = response.ReturnData
   227  		result.Storage = convertToProperMap(response.Storage)
   228  		result.Depth = int(response.Depth)
   229  		result.RefundCounter = response.GasRefund
   230  		result.Err = executor.RomErr(response.Error)
   231  
   232  		results = append(results, *result)
   233  	}
   234  	return &results, nil
   235  }
   236  
   237  func convertToBigIntArray(responses []string) ([]*big.Int, error) {
   238  	results := make([]*big.Int, 0, len(responses))
   239  
   240  	for _, response := range responses {
   241  		result, ok := new(big.Int).SetString(response, hex.Base)
   242  		if ok {
   243  			results = append(results, result)
   244  		} else {
   245  			return nil, fmt.Errorf("string %s is not valid", response)
   246  		}
   247  	}
   248  	return results, nil
   249  }
   250  
   251  func convertToProperMap(responses map[string]string) map[common.Hash]common.Hash {
   252  	results := make(map[common.Hash]common.Hash, len(responses))
   253  	for key, response := range responses {
   254  		results[common.HexToHash(key)] = common.HexToHash(response)
   255  	}
   256  	return results
   257  }
   258  
   259  func convertToExecutorTrace(callTrace *pb.CallTrace) instrumentation.ExecutorTrace {
   260  	trace := new(instrumentation.ExecutorTrace)
   261  	if callTrace != nil {
   262  		trace.Context = convertToContext(callTrace.Context)
   263  		trace.Steps = convertToInstrumentationSteps(callTrace.Steps)
   264  	}
   265  
   266  	return *trace
   267  }
   268  
   269  func convertToContext(context *pb.TransactionContext) instrumentation.Context {
   270  	return instrumentation.Context{
   271  		Type:         context.Type,
   272  		From:         context.From,
   273  		To:           context.To,
   274  		Input:        string(context.Data),
   275  		Gas:          fmt.Sprint(context.Gas),
   276  		Value:        context.Value,
   277  		Output:       string(context.Output),
   278  		GasPrice:     context.GasPrice,
   279  		OldStateRoot: string(context.OldStateRoot),
   280  		Time:         uint64(context.ExecutionTime),
   281  		GasUsed:      fmt.Sprint(context.GasUsed),
   282  	}
   283  }
   284  
   285  func convertToInstrumentationSteps(responses []*pb.TransactionStep) []instrumentation.Step {
   286  	results := make([]instrumentation.Step, 0, len(responses))
   287  	for _, response := range responses {
   288  		step := new(instrumentation.Step)
   289  		step.StateRoot = string(response.StateRoot)
   290  		step.Depth = int(response.Depth)
   291  		step.Pc = response.Pc
   292  		step.Gas = fmt.Sprint(response.Gas)
   293  		step.OpCode = fakevm.OpCode(response.Op).String()
   294  		step.Refund = fmt.Sprint(response.GasRefund)
   295  		step.Op = fmt.Sprint(response.Op)
   296  		err := executor.RomErr(response.Error)
   297  		if err != nil {
   298  			step.Error = err.Error()
   299  		}
   300  		step.Contract = convertToInstrumentationContract(response.Contract)
   301  		step.GasCost = fmt.Sprint(response.GasCost)
   302  		step.Stack = response.Stack
   303  		step.Memory = make([]byte, len(response.Memory))
   304  		copy(step.Memory, response.Memory)
   305  		step.ReturnData = make([]byte, len(response.ReturnData))
   306  		copy(step.ReturnData, response.ReturnData)
   307  		results = append(results, *step)
   308  	}
   309  	return results
   310  }
   311  
   312  func convertToInstrumentationContract(response *pb.Contract) instrumentation.Contract {
   313  	return instrumentation.Contract{
   314  		Address: response.Address,
   315  		Caller:  response.Caller,
   316  		Value:   response.Value,
   317  		Input:   string(response.Data),
   318  		Gas:     fmt.Sprint(response.Gas),
   319  	}
   320  }
   321  
   322  func convertToCounters(resp *pb.ProcessBatchResponse) ZKCounters {
   323  	return ZKCounters{
   324  		CumulativeGasUsed:    resp.CumulativeGasUsed,
   325  		UsedKeccakHashes:     resp.CntKeccakHashes,
   326  		UsedPoseidonHashes:   resp.CntPoseidonHashes,
   327  		UsedPoseidonPaddings: resp.CntPoseidonPaddings,
   328  		UsedMemAligns:        resp.CntMemAligns,
   329  		UsedArithmetics:      resp.CntArithmetics,
   330  		UsedBinaries:         resp.CntBinaries,
   331  		UsedSteps:            resp.CntSteps,
   332  	}
   333  }