Interperter.go
package vm
import (
"fmt"
"saseul/config"
"saseul/data/resourcechain"
"saseul/data/status"
"saseul/model"
"saseul/util/hasher"
"saseul/util/signer"
)
type Interpreter struct {
mode string
signedData *model.SignedData
code *model.Method
postProcess *model.Method
breakFlag bool
result string
weight int
methods map[string]func([]interface{}) interface{}
state string
process string
universals map[string]interface{}
locals map[string]interface{}
universalUpdates map[string]map[string]interface{}
localUpdates map[string]map[string]interface{}
}
func NewInterpreter() *Interpreter {
return &Interpreter{
methods: make(map[string]func([]interface{}) interface{}),
universals: make(map[string]interface{}),
locals: make(map[string]interface{}),
universalUpdates: make(map[string]map[string]interface{}),
localUpdates: make(map[string]map[string]interface{}),
}
}
// Reset ๋ฉ์๋๋ ์ธํฐํ๋ฆฌํฐ์ ์ํ๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
func (i *Interpreter) Reset(all bool) {
i.signedData = nil
i.code = nil
i.postProcess = nil
i.breakFlag = false
i.result = ""
i.weight = 0
if all {
i.state = ""
i.process = ""
i.universals = make(map[string]interface{})
i.locals = make(map[string]interface{})
}
i.universalUpdates = make(map[string]map[string]interface{})
i.localUpdates = make(map[string]map[string]interface{})
}
// Init ๋ฉ์๋๋ ์ธํฐํ๋ฆฌํฐ์ ๋ชจ๋๋ฅผ ์ด๊ธฐํํ๊ณ , ํด๋น ๋ชจ๋์ ํ์ํ ๋ฉ์๋๋ฅผ ๋ก๋ํฉ๋๋ค.
func (i *Interpreter) Init(mode string) {
if i.mode != mode {
i.mode = mode
i.methods = make(map[string]func([]interface{}) interface{})
i.loadMethod("BasicOperator")
i.loadMethod("ArithmeticOperator")
i.loadMethod("ComparisonOperator")
i.loadMethod("UtilOperator")
i.loadMethod("CastOperator")
i.loadMethod("ReadOperator")
if i.mode == "transaction" {
i.loadMethod("WriteOperator")
} else {
i.loadMethod("ChainOperator")
}
}
}
// LoadMethod ๋ฉ์๋๋ ์ฃผ์ด์ง ํธ๋ ์ดํธ์ ๋ฉ์๋๋ฅผ ์ธํฐํ๋ฆฌํฐ์ ๋ก๋ํฉ๋๋ค.
func (i *Interpreter) LoadMethod(traitName string) {
// ํธ๋ ์ดํธ์ ๋ฉ์๋๋ฅผ ๋ก๋ํ๋ ๋ก์ง์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
// ์๋ฅผ ๋ค์ด reflect ํจํค์ง๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
}
// Set ๋ฉ์๋๋ ์ธํฐํ๋ฆฌํฐ์ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) Set(data *model.SignedData, code *model.Method, postProcess *model.Method) {
i.signedData = data
i.code = code
i.postProcess = postProcess
i.breakFlag = false
i.weight = 0
i.result = "Conditional Error"
i.setDefaultValue()
}
// Process ๋ฉ์๋๋ ์ฃผ์ด์ง ABI๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
func (i *Interpreter) Process(abi interface{}) interface{} {
if abiArray, ok := abi.([]interface{}); ok {
for key, item := range abiArray {
prefix := string(key[0])
method := key[1:]
vars := i.Process(item)
if prefix == "$" && i.methods[method] != nil && isArray(vars) {
return i.methods[method].(func([]interface{}) interface{})(vars.([]interface{}))
} else {
abiArray[key] = vars
}
}
return abiArray
}
return abi
}
// setDefaultValue ๋ฉ์๋๋ ๊ธฐ๋ณธ ๊ฐ์ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) setDefaultValue() {
if i.signedData.Attributes("version") == nil {
i.signedData.Attributes("version", config.Version)
}
for name, parameter := range i.code.Parameters() {
requirements := parameter["requirements"].(bool)
if !requirements && i.signedData.Attributes(name) == nil {
defaultValue := parameter["default"]
i.signedData.Attributes(name, defaultValue)
}
}
if i.mode == "transaction" {
if i.signedData.Attributes("from") == nil {
i.signedData.Attributes("from", signer.Address(i.signedData.PublicKey))
}
if i.signedData.Attributes("hash") == nil {
i.signedData.Attributes("hash", i.signedData.Hash)
}
if i.signedData.Attributes("size") == nil {
i.signedData.Attributes("size", i.signedData.Size())
}
i.weight += i.signedData.Attributes("size").(int)
}
}
// ParameterValidity ๋ฉ์๋๋ ํ๋ผ๋ฏธํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํฉ๋๋ค.
func (i *Interpreter) ParameterValidity(errMsg *string) bool {
if i.mode == "transaction" {
from := i.signedData.Attributes("from").(string)
if from != signer.Address(i.signedData.PublicKey) {
*errMsg = fmt.Sprintf("Invalid from address: %s", from)
return false
}
}
for _, parameter := range i.code.Parameters() {
// parameter ๊ฐ์ฒด์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ก์ง์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
}
return true
}
// Read ๋ฉ์๋๋ ์ํ๋ฅผ ์ฝ์ด์ต๋๋ค.
func (i *Interpreter) Read() {
i.state = "READ"
i.process = "MAIN"
for _, execution := range i.code.Executions() {
i.Process(execution)
}
i.process = "POST"
for _, execution := range i.postProcess.Executions() {
i.Process(execution)
}
}
// Execute ๋ฉ์๋๋ ์ํ๋ฅผ ์คํํฉ๋๋ค.
func (i *Interpreter) Execute(result *string) bool {
executions := i.code.Executions()
postExecutions := i.postProcess.Executions()
i.state = "CONDITION"
i.process = "MAIN"
for key, execution := range executions {
executions[key] = i.Process(execution)
if i.breakFlag {
*result = i.result
return false
}
}
processLength := len(hasher.String(executions))
switch i.mode {
case "transaction":
if processLength > config.TxSizeLimit {
*result = "Too long processing."
return false
}
default:
if processLength > config.BlockTxSizeLimit {
*result = "Too long processing."
return false
}
}
i.process = "POST"
for key, execution := range postExecutions {
postExecutions[key] = i.Process(execution)
if i.breakFlag {
*result = i.result
return false
}
}
i.state = "EXECUTION"
i.process = "MAIN"
for key, execution := range executions {
executions[key] = i.Process(execution)
if i.breakFlag {
*result = i.result
return true
}
}
i.process = "POST"
for key, execution := range postExecutions {
postExecutions[key] = i.Process(execution)
if i.breakFlag {
*result = i.result
return true
}
}
return true
}
// LoadLocalStatus ๋ฉ์๋๋ ๋ก์ปฌ ์ํ๋ฅผ ๋ก๋ํฉ๋๋ค.
func (i *Interpreter) LoadLocalStatus() {
if len(i.locals) > 0 {
keys := make([]string, 0, len(i.locals))
for key := range i.locals {
keys = append(keys, key)
}
i.locals = status.Instance().LocalStatuses(keys)
}
}
// LoadUniversalStatus ๋ฉ์๋๋ ๋ฒ์ฉ ์ํ๋ฅผ ๋ก๋ํฉ๋๋ค.
func (i *Interpreter) LoadUniversalStatus() {
if len(i.universals) > 0 {
keys := make([]string, 0, len(i.universals))
for key := range i.universals {
keys = append(keys, key)
}
i.universals = status.Instance().UniversalStatuses(keys)
}
}
// LoadMinerStatus ๋ฉ์๋๋ ๋ง์ด๋ ์ํ๋ฅผ ๋ก๋ํฉ๋๋ค.
func (i *Interpreter) LoadMinerStatus(confirmedHeight int, miners []string) {
calculatedHeight := i.GetLocalStatus(config.CalculatedHeightHash(), 0).(int)
if confirmedHeight <= calculatedHeight {
return
}
for _, miner := range miners {
i.AddUniversalLoads(config.ResourceHash(miner))
}
block := resourcechain.Instance().Block(calculatedHeight + 1)
for _, receipt := range block.Receipts {
i.AddUniversalLoads(config.ResourceHash(receipt.Beneficiary))
}
}
// AddLocalLoads ๋ฉ์๋๋ ๋ก์ปฌ ์ํ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
func (i *Interpreter) AddLocalLoads(statusHash string) {
statusHash = hasher.FillHash(statusHash)
if _, exists := i.locals[statusHash]; !exists {
i.locals[statusHash] = nil
}
}
// AddUniversalLoads ๋ฉ์๋๋ ๋ฒ์ฉ ์ํ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
func (i *Interpreter) AddUniversalLoads(statusHash string) {
statusHash = hasher.FillHash(statusHash)
if _, exists := i.universals[statusHash]; !exists {
i.universals[statusHash] = nil
}
}
// SetLocalLoads ๋ฉ์๋๋ ๋ก์ปฌ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) SetLocalLoads(statusHash string, value interface{}) {
statusHash = hasher.FillHash(statusHash)
i.locals[statusHash] = value
}
// SetUniversalLoads ๋ฉ์๋๋ ๋ฒ์ฉ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) SetUniversalLoads(statusHash string, value interface{}) {
statusHash = hasher.FillHash(statusHash)
i.universals[statusHash] = value
}
// GetLocalStatus ๋ฉ์๋๋ ๋ก์ปฌ ์ํ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
func (i *Interpreter) GetLocalStatus(statusHash string, defaultValue interface{}) interface{} {
statusHash = hasher.FillHash(statusHash)
if value, exists := i.locals[statusHash]; exists {
return value
}
return defaultValue
}
// GetUniversalStatus ๋ฉ์๋๋ ๋ฒ์ฉ ์ํ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
func (i *Interpreter) GetUniversalStatus(statusHash string, defaultValue interface{}) interface{} {
statusHash = hasher.FillHash(statusHash)
if value, exists := i.universals[statusHash]; exists {
return value
}
return defaultValue
}
// SetUniversalStatus ๋ฉ์๋๋ ๋ฒ์ฉ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) SetUniversalStatus(statusHash string, value interface{}) bool {
if updates, exists := i.universalUpdates[statusHash]; exists {
updates["new"] = value
} else {
i.universalUpdates[statusHash] = map[string]interface{}{
"old": i.GetUniversalStatus(statusHash, nil),
"new": value,
}
}
statusHash = hasher.FillHash(statusHash)
i.universals[statusHash] = value
return true
}
// SetLocalStatus ๋ฉ์๋๋ ๋ก์ปฌ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค.
func (i *Interpreter) SetLocalStatus(statusHash string, value interface{}) bool {
if updates, exists := i.localUpdates[statusHash]; exists {
updates["new"] = value
} else {
i.localUpdates[statusHash] = map[string]interface{}{
"old": i.GetLocalStatus(statusHash, nil),
"new": value,
}
}
statusHash = hasher.FillHash(statusHash)
i.locals[statusHash] = value
return true
}Interpreter ๊ตฌ์กฐ์ฒด
์ฃผ์ ๋ฉ์๋
Last updated