Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions plutus-benchmark/bitwise/test/9.6/Ed25519.golden.uplc
Original file line number Diff line number Diff line change
Expand Up @@ -966,12 +966,12 @@
(case
ds
[ (\w
cont ->
rest ->
w) ]))
(case
ds
[ (\w
rest ->
cont ->
w) ])) ])
(next
ipv)) ])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Added

- Compilation support for the `multiIndexArray` builtin
([CIP-0156](https://cips.cardano.org/cip/CIP-0156)).
4 changes: 2 additions & 2 deletions plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ builtinNames =
, 'Builtins.lengthOfArray
, 'Builtins.listToArray
, 'Builtins.indexArray
, 'Builtins.multiIndexArray
, ''Builtins.BuiltinData
, 'Builtins.chooseData
, 'Builtins.equalsData
Expand Down Expand Up @@ -753,8 +754,7 @@ defineBuiltinTerms = do
PLC.LengthOfArray -> defineBuiltinInl 'Builtins.lengthOfArray
PLC.ListToArray -> defineBuiltinInl 'Builtins.listToArray
PLC.IndexArray -> defineBuiltinInl 'Builtins.indexArray
-- Not exposed to Plinth yet: core-language only for now (CIP-0156).
PLC.MultiIndexArray -> pure ()
PLC.MultiIndexArray -> defineBuiltinInl 'Builtins.multiIndexArray
-- Data
PLC.ChooseData -> defineBuiltinInl 'Builtins.chooseData
PLC.EqualsData -> defineBuiltinInl 'Builtins.equalsData
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[I 3, I 1, I 1, I 2]
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
(let
!multiIndexArray : all a. list integer -> array a -> list a
= multiIndexArray
in
multiIndexArray {data})
[2,0,0,1]
(let
!unitval : unit = ()
in
let
!mkNilData : unit -> list data = mkNilData
in
let
!mkI : integer -> data = iData
in
let
!mkCons : all a. a -> list a -> list a = mkCons
in
let
!listToArray : all a. list a -> array a = listToArray
in
listToArray
{data}
(mkCons
{data}
(mkI 1)
(mkCons {data} (mkI 2) (mkCons {data} (mkI 3) (mkNilData unitval)))))
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(program
1.1.0
((\multiIndexArray -> force multiIndexArray)
multiIndexArray
[2,0,0,1]
((\unitval ->
(\mkNilData ->
(\mkI ->
(\mkCons ->
(\listToArray ->
force listToArray
(force mkCons
(mkI 1)
(force mkCons
(mkI 2)
(force mkCons (mkI 3) (mkNilData unitval)))))
listToArray)
mkCons)
iData)
mkNilData)
())))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[I 3, I 1, I 1, I 2]
27 changes: 27 additions & 0 deletions plutus-tx-plugin/test/Array/9.6/compiledMultiIndexArray.golden.pir
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
(let
!multiIndexArray : all a. list integer -> array a -> list a
= multiIndexArray
in
multiIndexArray {data})
[2,0,0,1]
(let
!unitval : unit = ()
in
let
!mkNilData : unit -> list data = mkNilData
in
let
!mkI : integer -> data = iData
in
let
!mkCons : all a. a -> list a -> list a = mkCons
in
let
!listToArray : all a. list a -> array a = listToArray
in
listToArray
{data}
(mkCons
{data}
(mkI 1)
(mkCons {data} (mkI 2) (mkCons {data} (mkI 3) (mkNilData unitval)))))
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(program
1.1.0
((\multiIndexArray -> force multiIndexArray)
multiIndexArray
[2,0,0,1]
((\unitval ->
(\mkNilData ->
(\mkI ->
(\mkCons ->
(\listToArray ->
force listToArray
(force mkCons
(mkI 1)
(force mkCons
(mkI 2)
(force mkCons (mkI 3) (mkNilData unitval)))))
listToArray)
mkCons)
iData)
mkNilData)
())))
10 changes: 10 additions & 0 deletions plutus-tx-plugin/test/Array/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module Array.Spec where

import PlutusCore.Test (goldenUEval)
import PlutusTx
import PlutusTx.Builtins (toBuiltin)
import PlutusTx.Builtins.Internal
import PlutusTx.Test (goldenPirReadable, goldenUPlcReadable)
import Test.Tasty.Extras
Expand All @@ -33,6 +34,9 @@ smokeTests =
, goldenPirReadable "compiledIndexArray" compiledIndexArray
, goldenUPlcReadable "compiledIndexArray" compiledIndexArray
, goldenUEval "compiledIndexArray" [compiledIndexArray]
, goldenPirReadable "compiledMultiIndexArray" compiledMultiIndexArray
, goldenUPlcReadable "compiledMultiIndexArray" compiledMultiIndexArray
, goldenUEval "compiledMultiIndexArray" [compiledMultiIndexArray]
]
]

Expand Down Expand Up @@ -63,3 +67,9 @@ compiledIndexArray =
$$(compile [||indexArray||])
`unsafeApplyCode` compiledListToArray
`unsafeApplyCode` liftCodeDef 2

compiledMultiIndexArray :: CompiledCode (BuiltinList BuiltinData)
compiledMultiIndexArray =
$$(compile [||multiIndexArray||])
`unsafeApplyCode` liftCodeDef (toBuiltin ([2, 0, 0, 1] :: [Integer]))
`unsafeApplyCode` compiledListToArray
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Added

- `PlutusTx.Builtins.multiIndexArray`: the `multiIndexArray` builtin from
[CIP-0156](https://cips.cardano.org/cip/CIP-0156), returning the array elements at the given
indices and failing on any out-of-bounds index.
1 change: 1 addition & 0 deletions plutus-tx/plutus-tx.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ test-suite plutus-tx-test
main-is: Spec.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
other-modules:
Array.Spec
Blueprint.Definition.Fixture
Blueprint.Definition.Spec
Blueprint.Spec
Expand Down
1 change: 1 addition & 0 deletions plutus-tx/src/PlutusTx/Builtins.hs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ module PlutusTx.Builtins
, sopListToArray
, BI.lengthOfArray
, BI.indexArray
, BI.multiIndexArray

-- * Tracing
, trace
Expand Down
14 changes: 14 additions & 0 deletions plutus-tx/src/PlutusTx/Builtins/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,20 @@ indexArray (BuiltinArray v) i
| otherwise = Haskell.error "array index out of bounds"
{-# OPAQUE indexArray #-}

{-| Returns the elements at the given indices, in index-list order with duplicates preserved.
Fails if any index is not in the range @[0..j)@, where @j@ is the length of the array. -}
multiIndexArray :: BuiltinList BuiltinInteger -> BuiltinArray a -> BuiltinList a
multiIndexArray (BuiltinList is) (BuiltinArray v) =
case traverse lookupIndex is of
Just els -> BuiltinList els
Nothing -> Haskell.error "array index out of bounds"
where
len = toInteger (Vector.length v)
lookupIndex i
| 0 <= i && i < len = Just (Vector.unsafeIndex v (fromInteger i))
| otherwise = Nothing
{-# OPAQUE multiIndexArray #-}

{-
BLS12_381
-}
Expand Down
44 changes: 44 additions & 0 deletions plutus-tx/test/Array/Spec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{-# LANGUAGE TypeApplications #-}

module Array.Spec (arrayTests) where

import Control.Exception (ErrorCall)
import Data.Either (isLeft)
import PlutusCore.Test (pureTry)
import PlutusTx.Builtins.Internal qualified as BI

import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (Assertion, assertBool, testCase, (@?=))
import Prelude

-- The wrapper must fail exactly where the on-chain builtin fails: any index outside
-- @[0..length)@, including one exceeding @maxBound :: Int@, is an error rather than
-- a wrap-around lookup.
arrayTests :: TestTree
arrayTests =
testGroup
"Array"
[ testGroup
"multiIndexArray"
[ testCase "in-order with duplicates" $
unList (BI.multiIndexArray (BI.BuiltinList [2, 0, 0, 1]) arr) @?= [30, 10, 10, 20]
, testCase "index exceeding maxBound::Int fails" $
throwsErrorCall (BI.multiIndexArray (BI.BuiltinList [2 ^ (64 :: Int) + 2]) arr)
, testCase "out-of-bounds index fails even if the result is not fully demanded" $
throwsErrorCall
( case unList (BI.multiIndexArray (BI.BuiltinList [0, 3]) arr) of
x : _ -> x
[] -> 0
)
]
]
where
arr :: BI.BuiltinArray BI.BuiltinInteger
arr = BI.listToArray (BI.BuiltinList [10, 20, 30])

unList :: BI.BuiltinList a -> [a]
unList (BI.BuiltinList xs) = xs

throwsErrorCall :: a -> Assertion
throwsErrorCall x =
assertBool "expected the evaluation to fail" (isLeft (pureTry @ErrorCall x))
4 changes: 3 additions & 1 deletion plutus-tx/test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

module Main (main) where

import Array.Spec (arrayTests)
import Blueprint.Definition.Spec qualified
import Bool.Spec (boolTests)
import Builtins.Spec (builtinsTests)
Expand Down Expand Up @@ -41,7 +42,8 @@ tests :: TestTree
tests =
testGroup
"plutus-tx"
[ serdeTests
[ arrayTests
, serdeTests
, sqrtTests
, ratioTests
, bytestringTests
Expand Down
Loading