github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/std/native.go (about)

     1  package std
     2  
     3  import (
     4  	gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
     5  	"github.com/gnolang/gno/tm2/pkg/bech32"
     6  	"github.com/gnolang/gno/tm2/pkg/crypto"
     7  	"github.com/gnolang/gno/tm2/pkg/std"
     8  )
     9  
    10  func AssertOriginCall(m *gno.Machine) {
    11  	if !IsOriginCall(m) {
    12  		m.Panic(typedString("invalid non-origin call"))
    13  	}
    14  }
    15  
    16  func IsOriginCall(m *gno.Machine) bool {
    17  	return len(m.Frames) == 2
    18  }
    19  
    20  func CurrentRealmPath(m *gno.Machine) string {
    21  	if m.Realm != nil {
    22  		return m.Realm.Path
    23  	}
    24  	return ""
    25  }
    26  
    27  func GetChainID(m *gno.Machine) string {
    28  	return m.Context.(ExecContext).ChainID
    29  }
    30  
    31  func GetHeight(m *gno.Machine) int64 {
    32  	return m.Context.(ExecContext).Height
    33  }
    34  
    35  // getPrevFunctionNameFromTarget returns the last called function name (identifier) from the call stack.
    36  func getPrevFunctionNameFromTarget(m *gno.Machine, targetFunc string) string {
    37  	targetIndex := findTargetFuncIndex(m, targetFunc)
    38  	if targetIndex == -1 {
    39  		return ""
    40  	}
    41  	return findPrevFuncName(m, targetIndex)
    42  }
    43  
    44  // findTargetFuncIndex finds and returns the index of the target function in the call stack.
    45  func findTargetFuncIndex(m *gno.Machine, targetFunc string) int {
    46  	for i := len(m.Frames) - 1; i >= 0; i-- {
    47  		currFunc := m.Frames[i].Func
    48  		if currFunc != nil && currFunc.Name == gno.Name(targetFunc) {
    49  			return i
    50  		}
    51  	}
    52  	return -1
    53  }
    54  
    55  // findPrevFuncName returns the function name before the given index in the call stack.
    56  func findPrevFuncName(m *gno.Machine, targetIndex int) string {
    57  	for i := targetIndex - 1; i >= 0; i-- {
    58  		currFunc := m.Frames[i].Func
    59  		if currFunc != nil {
    60  			return string(currFunc.Name)
    61  		}
    62  	}
    63  	panic("function name not found")
    64  }
    65  
    66  func X_origSend(m *gno.Machine) (denoms []string, amounts []int64) {
    67  	os := m.Context.(ExecContext).OrigSend
    68  	return ExpandCoins(os)
    69  }
    70  
    71  func X_origCaller(m *gno.Machine) string {
    72  	return string(m.Context.(ExecContext).OrigCaller)
    73  }
    74  
    75  func X_origPkgAddr(m *gno.Machine) string {
    76  	return string(m.Context.(ExecContext).OrigPkgAddr)
    77  }
    78  
    79  func X_callerAt(m *gno.Machine, n int) string {
    80  	if n <= 0 {
    81  		m.Panic(typedString("GetCallerAt requires positive arg"))
    82  		return ""
    83  	}
    84  	// Add 1 to n to account for the GetCallerAt (gno fn) frame.
    85  	n++
    86  	if n > m.NumFrames() {
    87  		// NOTE: the last frame's LastPackage
    88  		// is set to the original non-frame
    89  		// package, so need this check.
    90  		m.Panic(typedString("frame not found"))
    91  		return ""
    92  	}
    93  	if n == m.NumFrames() {
    94  		// This makes it consistent with GetOrigCaller.
    95  		ctx := m.Context.(ExecContext)
    96  		return string(ctx.OrigCaller)
    97  	}
    98  	return string(m.MustLastCallFrame(n).LastPackage.GetPkgAddr().Bech32())
    99  }
   100  
   101  func X_getRealm(m *gno.Machine, height int) (address string, pkgPath string) {
   102  	var (
   103  		ctx           = m.Context.(ExecContext)
   104  		currentCaller crypto.Bech32Address
   105  		// Keeps track of the number of times currentCaller
   106  		// has changed.
   107  		changes int
   108  	)
   109  
   110  	for i := m.NumFrames() - 1; i > 0; i-- {
   111  		fr := m.Frames[i]
   112  		if fr.LastPackage == nil || !fr.LastPackage.IsRealm() {
   113  			continue
   114  		}
   115  
   116  		// LastPackage is a realm. Get caller and pkgPath, and compare against
   117  		// current* values.
   118  		caller := fr.LastPackage.GetPkgAddr().Bech32()
   119  		pkgPath := fr.LastPackage.PkgPath
   120  		if caller != currentCaller {
   121  			if changes == height {
   122  				return string(caller), pkgPath
   123  			}
   124  			currentCaller = caller
   125  			changes++
   126  		}
   127  	}
   128  
   129  	// Fallback case: return OrigCaller.
   130  	return string(ctx.OrigCaller), ""
   131  }
   132  
   133  func X_derivePkgAddr(pkgPath string) string {
   134  	return string(gno.DerivePkgAddr(pkgPath).Bech32())
   135  }
   136  
   137  func X_encodeBech32(prefix string, bytes [20]byte) string {
   138  	b32, err := bech32.ConvertAndEncode(prefix, bytes[:])
   139  	if err != nil {
   140  		panic(err) // should not happen
   141  	}
   142  	return b32
   143  }
   144  
   145  func X_decodeBech32(addr string) (prefix string, bytes [20]byte, ok bool) {
   146  	prefix, bz, err := bech32.Decode(addr)
   147  	if err != nil || len(bz) != 20 {
   148  		return "", [20]byte{}, false
   149  	}
   150  	return prefix, [20]byte(bz), true
   151  }
   152  
   153  func typedString(s string) gno.TypedValue {
   154  	tv := gno.TypedValue{T: gno.StringType}
   155  	tv.SetString(gno.StringValue(s))
   156  	return tv
   157  }
   158  
   159  func ExpandCoins(c std.Coins) (denoms []string, amounts []int64) {
   160  	denoms = make([]string, len(c))
   161  	amounts = make([]int64, len(c))
   162  	for i, coin := range c {
   163  		denoms[i] = coin.Denom
   164  		amounts[i] = coin.Amount
   165  	}
   166  	return denoms, amounts
   167  }
   168  
   169  func CompactCoins(denoms []string, amounts []int64) std.Coins {
   170  	coins := make(std.Coins, len(denoms))
   171  	for i := range coins {
   172  		coins[i] = std.Coin{Denom: denoms[i], Amount: amounts[i]}
   173  	}
   174  	return coins
   175  }