mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
package program
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/formancehq/ledger/internal/machine"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type Program struct {
|
|
Instructions []byte
|
|
Resources []Resource
|
|
NeededBalances map[machine.Address]map[machine.Address]struct{}
|
|
|
|
ReadLockAccounts []machine.Address
|
|
WriteLockAccounts []machine.Address
|
|
}
|
|
|
|
func (p Program) String() string {
|
|
out := "Program:\nINSTRUCTIONS\n"
|
|
for i := 0; i < len(p.Instructions); i++ {
|
|
out += fmt.Sprintf("%02d----- ", i)
|
|
switch p.Instructions[i] {
|
|
case OP_APUSH:
|
|
out += "OP_APUSH "
|
|
address := binary.LittleEndian.Uint16(p.Instructions[i+1 : i+3])
|
|
out += fmt.Sprintf("#%d\n", address)
|
|
i += 2
|
|
default:
|
|
out += OpcodeName(p.Instructions[i]) + "\n"
|
|
}
|
|
}
|
|
|
|
out += fmt.Sprintln("RESOURCES")
|
|
i := 0
|
|
for i = 0; i < len(p.Resources); i++ {
|
|
out += fmt.Sprintf("%02d ", i)
|
|
out += fmt.Sprintf("%v\n", p.Resources[i])
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (p *Program) ParseVariables(vars map[string]machine.Value) (map[string]machine.Value, error) {
|
|
variables := make(map[string]machine.Value)
|
|
for _, res := range p.Resources {
|
|
if variable, ok := res.(Variable); ok {
|
|
if val, ok := vars[variable.Name]; ok && val.GetType() == variable.Typ {
|
|
variables[variable.Name] = val
|
|
switch val.GetType() {
|
|
case machine.TypeAccount:
|
|
if err := machine.ValidateAccountAddress(val.(machine.AccountAddress)); err != nil {
|
|
return nil, errors.Wrapf(err, "invalid variable $%s value '%s'",
|
|
variable.Name, string(val.(machine.AccountAddress)))
|
|
}
|
|
case machine.TypeAsset:
|
|
if err := machine.ValidateAsset(val.(machine.Asset)); err != nil {
|
|
return nil, errors.Wrapf(err, "invalid variable $%s value '%s'",
|
|
variable.Name, string(val.(machine.Asset)))
|
|
}
|
|
case machine.TypeMonetary:
|
|
if err := machine.ParseMonetary(val.(machine.Monetary)); err != nil {
|
|
return nil, errors.Wrapf(err, "invalid variable $%s value '%s'",
|
|
variable.Name, val.(machine.Monetary).String())
|
|
}
|
|
case machine.TypePortion:
|
|
if err := machine.ValidatePortionSpecific(val.(machine.Portion)); err != nil {
|
|
return nil, errors.Wrapf(err, "invalid variable $%s value '%s'",
|
|
variable.Name, val.(machine.Portion).String())
|
|
}
|
|
case machine.TypeString:
|
|
case machine.TypeNumber:
|
|
default:
|
|
return nil, fmt.Errorf("unsupported type for variable $%s: %s",
|
|
variable.Name, val.GetType())
|
|
}
|
|
delete(vars, variable.Name)
|
|
} else if val, ok := vars[variable.Name]; ok && val.GetType() != variable.Typ {
|
|
return nil, fmt.Errorf("wrong type for variable $%s: %s instead of %s",
|
|
variable.Name, variable.Typ, val.GetType())
|
|
} else {
|
|
return nil, fmt.Errorf("missing variable $%s", variable.Name)
|
|
}
|
|
}
|
|
}
|
|
for name := range vars {
|
|
return nil, fmt.Errorf("extraneous variable $%s", name)
|
|
}
|
|
return variables, nil
|
|
}
|
|
|
|
func (p *Program) ParseVariablesJSON(vars map[string]string) (map[string]machine.Value, error) {
|
|
variables := make(map[string]machine.Value)
|
|
for _, res := range p.Resources {
|
|
if param, ok := res.(Variable); ok {
|
|
data, ok := vars[param.Name]
|
|
if !ok {
|
|
return nil, fmt.Errorf("missing variable $%s", param.Name)
|
|
}
|
|
val, err := machine.NewValueFromString(param.Typ, data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"invalid JSON value for variable $%s of type %v: %w",
|
|
param.Name, param.Typ, err)
|
|
}
|
|
variables[param.Name] = val
|
|
delete(vars, param.Name)
|
|
}
|
|
}
|
|
for name := range vars {
|
|
return nil, fmt.Errorf("extraneous variable $%s", name)
|
|
}
|
|
return variables, nil
|
|
}
|