Văn bản gốc: Thực hiện Giao ước bắc cầu trên Bitcoin được kích hoạt OP_CAT: Bằng chứng về khái niệm
Dịch thuật và hiệu đính: Cộng đồng người Hoa Starknet
📑 Vui lòng ghi rõ nguồn khi tái bản🕹️
Thông tin nhanh nổi bật
Một cuộc thảo luận chuyên sâu về việc xây dựng hợp đồng cầu nối demo trên Bitcoin để đặt nền tảng cho cầu nối cấp sản xuất của Starknet
Triển khai bốn hợp đồng thông minh: công cụ tổng hợp tiền gửi và rút tiền, công mở rộng cầu nối và rút tiền
Tận dụng các hợp đồng đệ quy và Merkle trees để gửi và rút tiền hàng loạt một cách hiệu quả trong khi vẫn duy trì tính toàn vẹn và bảo mật của tài khoản người dùng
giới thiệu
Trong bài viết này, chúng ta xem xét sâu hơn cách sCrypt xây dựng hợp đồng cầu nối demo trên Bitcoin. Việc triển khai bằng chứng khái niệm này được thiết kế để đặt nền móng cho cầu nối cấp sản xuất cho mạng Starknet Lớp 2 (L2). Thiết kế của cầu nối cho phép hợp nhất nhiều giao dịch yêu cầu gửi hoặc rút tiền thành một giao dịch gốc duy nhất và được tích hợp vào hợp đồng cầu nối chính, cập nhật trạng thái của nó, bao gồm một tập hợp các tài khoản được tổ chức theo Merkle trees.
Vì tập lệnh hợp đồng cầu nối rất phức tạp nên tại sCrypt chúng tôi sử dụng ngôn ngữ dành riêng cho miền sCrypt (DSL) để viết phần triển khai của nó.
Tổng quan
Cây cầu bao gồm một tập lệnh Bitcoin đệ quy. Ở đây, "hợp đồng" có nghĩa là tập lệnh khóa có thể áp đặt các điều kiện cho giao dịch chi tiêu, trong khi "đệ quy" có nghĩa là các quy tắc trên đủ mạnh để đạt được trạng thái và logic liên tục trên Chuỗi(đây là yêu cầu cơ bản đối với bất kỳ giao dịch nào trên chuỗi). - Chuỗi hợp đồng thông minh).
Tập lệnh tồn tại trong sê-ri giao dịch, mỗi giao dịch áp đặt các ràng buộc lên cấu trúc của các giao dịch tiếp theo và các giao dịch tiếp theo sẽ mở khóa đầu ra của giao dịch hiện tại. Bất cứ khi nào một giao dịch mới được thêm vào Chuỗi này, nó thể hiện một bản cập nhật cho trạng thái cầu nối. Do đó, phần cuối của Chuỗi này giữ trạng thái cầu hiện tại.
Trạng thái hợp đồng—cụ thể là giá trị băm của nó—được lưu trữ trong đầu ra OP_RETURN không tiêu thụ được. Mặc dù chúng tôi sẽ không sử dụng UTXO này nhưng dữ liệu của nó có thể được kiểm tra khi thực thi tập lệnh hợp đồng. Cụ thể, state giữ hàm băm gốc của Merkle trees chứa dữ liệu tài khoản, như hình dưới đây:
Merkle trees này chứa dữ liệu cho một nhóm vị trí tài khoản cố định. Nút lá chứa các giá trị băm của dữ liệu tài khoản tương ứng của chúng, trong đó địa chỉ và số dư. Để thể hiện các vị trí tài khoản trống, các vị trí này được đánh dấu bằng 0 byte.
Lần lần cập nhật của bridge sẽ khiến cây tài khoản thay đổi. Để tạo điều kiện thuận lợi cho quá trình cập nhật này, chúng tôi dựa vào bằng chứng Merkle, bằng chứng có khả năng xác minh rất hiệu quả trong tập lệnh Bitcoin. Bản cập nhật chủ yếu bao gồm hai bước. Đầu tiên, chúng tôi xác minh bằng chứng Merkle để cho thấy rằng Merkle trees chứa trạng thái hiện tại của một tài khoản cụ thể. Sau đó, sau khi tính toán trạng thái mới của tài khoản, chúng tôi sử dụng nút phụ trợ tương tự từ bằng chứng Merkle đã nói ở trên để lấy ra hàm băm gốc mới.
Cập nhật có thể là gửi tiền hoặc rút tiền. Cây cầu có thể thực hiện các hoạt động hàng loạt của các cập nhật này trong một giao dịch.
tiền gửi
Mục tiêu của chúng tôi là cho phép người dùng gửi yêu cầu gửi hoặc rút tiền một cách độc lập. Để thực hiện việc này, người dùng tạo các giao dịch thanh toán vào hợp đồng tổng hợp tiền gửi hoặc rút tiền tương ứng. Hợp đồng tổng hợp các yêu cầu này vào Merkle trees. Hàm băm gốc của cây này có thể được hợp nhất vào hợp đồng cầu nối chính, sau đó xử lý mọi khoản tiền gửi hoặc rút tiền.
Trong giao dịch tiền gửi, ngoài việc băm dữ liệu tiền gửi và xây dựng Merkle trees, hợp đồng còn đảm bảo rằng số satoshi tiền gửi bị khóa trong đầu ra hợp đồng được tích lũy theo cách chính xác đến nút của cây. Hợp đồng tổng hợp đảm bảo rằng chỉ hợp đồng thông minh trên Chuỗi chính xác mới có thể sử dụng số tiền này. (Tất nhiên, trong hoàn cảnh sản xuất, chúng tôi cũng sẽ cho phép người dùng hủy giao dịch gửi tiền của họ).
Thiết kế của cấu trúc cây này xuất phát từ những hạn chế trong việc xây dựng tập lệnh hợp đồng, không cho phép các giao dịch chứa quá nhiều đầu vào và đầu ra. Cấu trúc cây cho phép chúng tôi mở mở rộng theo thông lượng có thể tùy ý.
Yêu cầu rút tiền
Việc tổng hợp các yêu cầu rút tiền cũng tương tự như việc gửi tiền, có một số điểm khác biệt. Đầu tiên, chúng ta cần một phương pháp xác thực để người dùng có thể rút tiền từ tài khoản của mình. Điều này khác với tiền gửi, nơi bất kỳ ai cũng có thể gửi tiền vào bất kỳ tài khoản nào, tương tự như cách sử dụng địa chỉ Bitcoin. Việc xác thực được thực hiện ở cấp độ nút lá của cây tổng hợp. Hợp đồng tổng hợp yêu cầu rút tiền sẽ kiểm tra xem địa chỉ rút tiền có khớp với địa chỉ P2WPKH đầu tiên được nhập trong giao dịch lá hay không.
Điều này đảm bảo rằng chủ sở hữu địa chỉ chấp thuận việc rút tiền vì họ đã ký giao dịch yêu cầu rút tiền. Một điểm khác biệt nhỏ so với tổng hợp tiền gửi là chúng tôi cũng băm số tiền tích lũy trung gian và chuyển chúng lên cấu trúc cây. Điều này là do chúng tôi cần dữ liệu này khi mở rộng quy mô rút tiền, sẽ nói thêm về điều đó sau.
Những độc giả tinh ý có thể nhận thấy các vấn đề tiềm ẩn với mô hình xác thực yêu cầu rút tiền này. Điều gì sẽ xảy ra nếu một nhà điều hành quyết định gian lận và tạo một giao dịch ở gốc của cây tổng hợp có dữ liệu được ngụy tạo cục bộ thông qua các yêu cầu rút tiền giả không được xác thực? Chúng ta cần một phương pháp hiệu quả để xác minh rằng giao dịch gốc xuất phát từ giao dịch lá hợp lệ.
Để giải quyết vấn đề này, chúng tôi thực hiện cái gọi là "kiểm tra nguồn gốc". Về cơ bản, chúng tôi có hợp đồng tổng hợp kiểm tra giao dịch trước đó và hai giao dịch trước đó, "giao dịch tổ tiên" của nó. Hợp đồng xác minh rằng các giao dịch này có chứa cùng một tập lệnh hợp đồng và thực hiện các bước kiểm tra giống nhau. Bằng cách này, chúng tôi thực hiện kiểm tra lịch sử giao dịch quy nạp. Vì hai giao dịch đầu tiên thực hiện các bước kiểm tra giống như hợp đồng hiện tại nên chúng tôi có thể xác nhận rằng "tổ tiên" của các giao dịch này cũng thực hiện các bước kiểm tra tương tự, cho đến tận nút lá (tức là giao dịch gốc).
Tất nhiên, chúng tôi đã thực hiện xác nhận trên cả hai nhánh của cây. Do đó, tổng cộng có tối đa sáu giao dịch được kiểm tra cho mỗi giao dịch nút tổng hợp.
Mở rộng rút tiền
Bây giờ chúng ta hãy đến phần cuối cùng của giải pháp: mở rộng rút tiền. Sau khi xử lý một loạt yêu cầu rút tiền, hợp đồng cầu nối chính buộc đầu ra phải thanh toán tổng số tiền rút cho hợp đồng mở rộng. Chúng ta có thể coi hợp đồng này là quá trình ngược lại với những gì hợp đồng tổng hợp yêu cầu rút tiền thực hiện. Nó bắt đầu từ nút của cây rút tiền và mở rộng nó thành hai nhánh, mỗi nhánh chứa số tiền rút tương ứng phải trả cho nhánh đó. Quá trình này tiếp tục cho đến nút lá của cây rút lui. Các giao dịch lá thực thi một đầu ra thanh toán đơn giản đến địa chỉ của chủ tài khoản cho số tiền họ yêu cầu rút.
Phương pháp thực hiện
Để triển khai hợp đồng cầu nối của mình, chúng tôi đã phát triển bốn hợp đồng thông minh sCrypt, mỗi hợp đồng xử lý các khía cạnh khác nhau của hệ thống. Trong phần này, chúng tôi sẽ phác thảo ngắn gọn chức năng của từng hợp đồng.
Hợp đồng tổng hợp tiền gửi
Hợp đồng Tổng hợp tiền gửi tổng hợp các khoản tiền gửi riêng lẻ vào Merkle trees, sau đó được hợp nhất vào hợp đồng cầu nối chính. Việc tổng hợp này cho phép xử lý tiền gửi hàng loạt, giảm số lượng giao dịch cần được xử lý riêng lẻ bởi cầu nối. Ngoài ra, nó cho phép người dùng gửi tiền gửi một cách độc lập, sau đó sẽ được các nhà khai thác xử lý.
class DepositAggregator extends SmartContract { @prop() operator: PubKey @prop() bridgeSPK: ByteString /** * Covenant used for the aggregation of deposits. * * @param operator - Public key of bridge operator. * @param bridgeSPK - P2TR script of the bridge state covenant. Includes length prefix! */ constructor(operator: PubKey, bridgeSPK: ByteString) { super(...arguments) this.operator = operator this.bridgeSPK = bridgeSPK } @method() public aggregate( shPreimage: SHPreimage, isPrevTxLeaf:boolean, sigOperator: Sig, prevTx0: AggregatorTransaction, prevTx1: AggregatorTransaction, // Additional parameters... ) { // Validation steps... } @method() public finalize( shPreimage: SHPreimage, sigOperator: Sig, prevTx: AggregatorTransaction, ancestorTx0: AggregatorTransaction, ancestorTx1: AggregatorTransaction, bridgeTxId: Sha256, fundingPrevout: ByteString ) { // Finalization steps... } }
Hàm xây dựng hợp đồng có hai tham số:
nhà điều hành: Khóa công khai của nhà điều hành cầu nối có thẩm quyền tổng hợp tiền gửi.
bridgeSPK: Khóa công khai tập lệnh (SPK) của hợp đồng cầu nối chính, đảm bảo rằng tổng số tiền gửi được hợp nhất một cách chính xác.
Chức năng cốt lõi của công cụ tổng hợp tiền gửi được gói gọn trong phương pháp"tổng hợp". Phương pháp này thực hiện các bước sau:
Xác minh tiền ảnh Sighash và chữ ký nhà điều hành : Đảm bảo rằng giao dịch được nhà điều hành cầu nối ủy quyền và tiền ảnh Sighash có định dạng chính xác và thuộc về giao dịch đang được thực hiện. Tìm hiểu thêm về xác minh tiền ảnh bằng tiếng thở dài trong bài viết này .
// Check sighash preimage. const s = SigHashUtils.checkSHPreimage(shPreimage) assert(this.checkSig(s, SigHashUtils.Gx)) // Check operator signature. assert(this.checkSig(sigOperator, this.operator))
Xây dựng và xác thực ID giao dịch tiền nhiệm : Kiểm tra xem các giao dịch tiền nhiệm tổng hợp có hợp lệ và được tham chiếu chính xác hay không.
// Construct previous transaction ID. const prevTxId = AggregatorUtils.getTxId(prevTx, false) // Verify that the transaction unlocks the specified outputs. const hashPrevouts = AggregatorUtils.getHashPrevouts( bridgeTxId, prevTxId, fundingPrevout ) assert(hashPrevouts == shPreimage.hashPrevouts)
Tập hợp Merkle trees : Xác minh rằng dữ liệu tiền gửi được chuyển dưới dạng hàm băm nhân chứng khớp với trạng thái được lưu trữ trong giao dịch trước đó.
const hashData0 = DepositAggregator.hashDepositData(depositData0) const hashData1 = DepositAggregator.hashDepositData(depositData1) assert(hashData0 == prevTx0.hashData) assert(hashData1 == prevTx1.hashData)
Xác thực số tiền : Xác nhận rằng số tiền ở đầu ra phía trước khớp với số tiền gửi được chỉ định, đảm bảo rằng số tiền được tính toán chính xác trong tổng hợp.
// Check that the prev outputs actually carry the specified amount // of satoshis. The amount values can also carry aggregated amounts, // in case we're not aggregating leaves anymore. assert( GeneralUtils.padAmt(depositData0.amount) == prevTx0.outputContractAmt ) assert( GeneralUtils.padAmt(depositData1.amount) == prevTx1.outputContractAmt )
Cập nhật trạng thái : Tính giá trị băm mới bằng cách ghép các giá trị băm của các giao dịch trước đó và cập nhật trạng thái trong đầu ra OP_RETURN.
// Concatinate hashes from previous aggregation txns (or leaves) // and compute new hash. Store this new hash in the state OP_RETURN // output. const newHash = hash256(prevTx0.hashData + prevTx1.hashData) const stateOut = GeneralUtils.getStateOutput(newHash)
Ngăn chặn tấn công truy cập lại : Thực thi các tập lệnh và số lượng đầu ra nghiêm ngặt để ngăn chặn các sửa đổi trái phép hoặc chi tiêu gấp đôi.
// Sum up aggregated amounts and construct contract output. const contractOut = GeneralUtils.getContractOutput( depositData0.amount + depositData1.amount, prevTx0.outputContractSPK ) // Recurse. Send to aggregator with updated hash. const outputs = contractOut + stateOut assert( sha256(outputs) == shPreimage.hashOutputs )
Sau khi tổng hợp tiền đặt cọc, chúng phải được hợp nhất vào hợp đồng cầu chính. Quá trình này được xử lý bằng phương pháp"hoàn thiện", các bước bao gồm:
Xác minh các giao dịch trước đó : Tương tự như phương pháp"tổng hợp", xác minh các giao dịch trước đó để đảm bảo tính toàn vẹn của dữ liệu tổng hợp.
Tích hợp với hợp đồng cầu nối : Kiểm tra xem số tiền gửi tổng hợp có được hợp nhất chính xác vào hợp đồng cầu nối chính hay không bằng cách tham chiếu ID giao dịch của cầu nối và khóa chung tập lệnh.
Mã nguồn hoàn chỉnh của hợp đồng tổng hợp tiền gửi có thể được xem trên GitHub .
Hợp đồng tổng hợp rút tiền
Hợp đồng Tổng hợp rút tiền được thiết kế để tổng hợp các yêu cầu rút tiền riêng lẻ vào Merkle trees, tương tự như cách các công cụ tổng hợp tiền gửi xử lý tiền gửi. Tuy nhiên, hoạt động rút tiền yêu cầu xác thực bổ sung để đảm bảo rằng chỉ những chủ tài khoản hợp pháp mới có thể rút tiền từ tài khoản của họ.
class WithdrawalAggregator extends SmartContract { @prop() operator: PubKey @prop() bridgeSPK: ByteString /** * Covenant used for the aggregation of withdrawal requests. * * @param operator - Public key of bridge operator. * @param bridgeSPK - P2TR script of the bridge state covenant. Includes length prefix! */ constructor(operator: PubKey, bridgeSPK: ByteString) { super(...arguments) this.operator = operator this.bridgeSPK = bridgeSPK } @method() public aggregate( shPreimage: SHPreimage, isPrevTxLeaf:boolean, sigOperator: Sig, prevTx0: AggregatorTransaction, prevTx1: AggregatorTransaction, // Additional parameters... ) { // Validation and aggregation logic... } @method() public finalize( shPreimage: SHPreimage, sigOperator: Sig, prevTx: AggregatorTransaction, ancestorTx0: AggregatorTransaction, ancestorTx1: AggregatorTransaction, bridgeTxId: Sha256, fundingPrevout: ByteString ) { // Validation logic... } }
Chức năng cốt lõi của công cụ tổng hợp rút tiền được gói gọn trong phương pháp"tổng hợp", phương pháp hiện các bước sau:
// Check sighash preimage. const s = SigHashUtils.checkSHPreimage(shPreimage) assert(this.checkSig(s, SigHashUtils.Gx)) // Check operator signature. assert(this.checkSig(sigOperator, this.operator))
Xây dựng và xác thực ID giao dịch tiền nhiệm : Quá trình này xác minh rằng giao dịch tiền nhiệm tổng hợp là hợp lệ và được tham chiếu chính xác.
// Construct previous transaction IDs. const prevTxId0 = AggregatorUtils.getTxId(prevTx0, isPrevTxLeaf) const prevTxId1 = AggregatorUtils.getTxId(prevTx1, isPrevTxLeaf) // Verify that the previous transactions are unlocked by the current transaction. const hashPrevouts = AggregatorUtils.getHashPrevouts( prevTxId0, prevTxId1, fundingPrevout ) assert(hashPrevouts == shPreimage.hashPrevouts)
Bằng chứng xác minh quyền sở hữu : Việc xác minh các giao dịch bằng chứng quyền sở hữu đảm bảo rằng chỉ chủ sở hữu hợp pháp mới có thể rút tiền từ tài khoản.
- Bằng chứng về quyền sở hữu giao dịch : Một giao dịch chứng minh quyền kiểm soát địa chỉ rút tiền. Hợp đồng sẽ kiểm tra xem địa chỉ trong yêu cầu rút tiền có khớp với địa chỉ trong bằng chứng giao dịch quyền sở hữu hay không.
if (isPrevTxLeaf) { // Construct ownership proof transaction IDs. const ownershipProofTxId0 = WithdrawalAggregator.getOwnershipProofTxId(ownProofTx0) const ownershipProofTxId1 = WithdrawalAggregator.getOwnershipProofTxId(ownProofTx1) // Check that the leaf transactions unlock the ownership proof transactions. assert(ownershipProofTxId0 + toByteString('0000000000ffffffff') == prevTx0.inputContract0) assert(ownershipProofTxId1 + toByteString('0000000000ffffffff') == prevTx1.inputContract0) // Verify that the withdrawal addresses match the addresses in the ownership proof transactions. assert(withdrawalData0.address == ownProofTx0.outputAddrP2WPKH) assert(withdrawalData1.address == ownProofTx1.outputAddrP2WPKH) }
Kiểm tra gốc thông qua "giao dịch tổ tiên" : Tương tự như công cụ tổng hợp tiền gửi, hợp đồng thực hiện kiểm tra quy nạp bằng cách xác thực các giao dịch tổ tiên. Điều này đảm bảo tính toàn vẹn của lịch sử giao dịch và ngăn chặn các nhà khai thác chèn các yêu cầu rút tiền trái phép.
if (!isPrevTxLeaf) { // Construct ancestor transaction IDs. const ancestorTxId0 = AggregatorUtils.getTxId(ancestorTx0, isAncestorLeaf) const ancestorTxId1 = AggregatorUtils.getTxId(ancestorTx1, isAncestorLeaf) const ancestorTxId2 = AggregatorUtils.getTxId(ancestorTx2, isAncestorLeaf) const ancestorTxId3 = AggregatorUtils.getTxId(ancestorTx3, isAncestorLeaf) // Verify that previous transactions unlock the ancestor transactions. assert(prevTx0.inputContract0 == ancestorTxId0 + toByteString('0000000000ffffffff')) assert(prevTx0.inputContract1 == ancestorTxId1 + toByteString('0000000000ffffffff')) assert(prevTx1.inputContract0 == ancestorTxId2 + toByteString('0000000000ffffffff')) assert(prevTx1.inputContract1 == ancestorTxId3 + toByteString('0000000000ffffffff')) // Ensure that the ancestor transactions have the same contract SPK. assert(prevTx0.outputContractSPK == ancestorTx0.outputContractSPK) assert(prevTx0.outputContractSPK == ancestorTx1.outputContractSPK) assert(prevTx0.outputContractSPK == ancestorTx2.outputContractSPK) assert(prevTx0.outputContractSPK == ancestorTx3.outputContractSPK) }
Xác minh số tiền và tính tổng số tiền : Phương pháp này tính toán tổng số tiền cần rút bằng cách cộng số tiền yêu cầu rút tiền hoặc tổng hợp trước đó.
let sumAmt = 0n if (isPrevTxLeaf) { sumAmt = withdrawalData0.amount + withdrawalData1.amount } else { sumAmt = aggregationData0.sumAmt + aggregationData1.sumAmt }
Cập nhật trạng thái : Tính toán hàm băm mới trong đó tổng số giá trị băm của các giao dịch trước đó và số tiền rút. Giá trị băm này được lưu trữ trong đầu ra OP_RETURN để cập nhật trạng thái.
// Create new aggregation data. const newAggregationData: AggregationData = { prevH0: prevTx0.hashData, prevH1: prevTx1.hashData, sumAmt } const newHash = WithdrawalAggregator.hashAggregationData(newAggregationData) const stateOut = GeneralUtils.getStateOutput(newHash)
Ngăn chặn tấn công reentrancy và thực thi đầu ra : Đảm bảo các đầu ra được xác định nghiêm ngặt để ngăn chặn các cuộc tấn công sửa đổi trái phép hoặc tấn công reentrancy.
// Construct contract output with the minimum dust amount. const contractOut = GeneralUtils.getContractOutput( 546n, prevTx0.outputContractSPK ) // Ensure outputs match the expected format. const outputs = contractOut + stateOut assert( sha256(outputs) == shPreimage.hashOutputs, )
Mã nguồn hoàn chỉnh của hợp đồng tổng hợp rút tiền có thể được xem trên GitHub .
hợp đồng cầu
Hợp đồng Bridge là thành phần cốt lõi trong hệ thống của chúng tôi và là hợp đồng chính để duy trì trạng thái của bridge, bao gồm các tài khoản và số dư được tổ chức trong Merkle trees . Nó xử lý các hoạt động gửi và rút tiền bằng cách tích hợp với hợp đồng tổng hợp mà chúng ta đã thảo luận trước đó.
class Bridge extends SmartContract { @prop() operator: PubKey @prop() expanderSPK: ByteString constructor( operator: PubKey, expanderSPK: ByteString ) { super(...arguments) this.operator = operator this.expanderSPK = expanderSPK } @method() public deposit( shPreimage: SHPreimage, sigOperator: Sig, prevTx: BridgeTransaction, // Previous bridge update transaction. aggregatorTx: AggregatorTransaction, // Root aggregator transaction. fundingPrevout: ByteString, deposits: FixedArray<DepositData, typeof MAX_NODES_AGGREGATED>, accounts: FixedArray<AccountData, typeof MAX_NODES_AGGREGATED>, depositProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED>, accountProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED> ) { // Method implementation... } @method() public withdrawal( shPreimage: SHPreimage, sigOperator: Sig, prevTx: BridgeTransaction, // Previous bridge update transaction. aggregatorTx: AggregatorTransaction, // Root aggregator transaction. fundingPrevout: ByteString, withdrawals: FixedArray<WithdrawalData, typeof MAX_NODES_AGGREGATED>, accounts: FixedArray<AccountData, typeof MAX_NODES_AGGREGATED>, intermediateSumsArr: FixedArray<IntermediateValues, typeof MAX_NODES_AGGREGATED>, withdrawalProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED>, accountProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED> ) { // Method implementation... } }
Hàm xây dựng hợp đồng có hai tham số:
*người vận hành:* Khóa chung của người điều hành cầu nối có quyền cập nhật trạng thái cầu nối.
ExpanderSPK *: Khóa công khai tập mở rộng (SPK) của hợp đồng WithdrawalExpander, được sử dụng trong quá trình rút tiền.
Phương thức gửi tiền có trách nhiệm xử lý các giao dịch gửi tiền tổng hợp và cập nhật số dư tài khoản tương ứng.
@method() public deposit( shPreimage: SHPreimage, sigOperator: Sig, prevTx: BridgeTransaction, // Previous bridge update transaction. aggregatorTx: AggregatorTransaction, // Root aggregator transaction. fundingPrevout: ByteString, deposits: FixedArray<DepositData, typeof MAX_NODES_AGGREGATED>, accounts: FixedArray<AccountData, typeof MAX_NODES_AGGREGATED>, depositProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED>, accountProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED> ) { // Common validation steps... // (Same as in previous contracts: sighash preimage check, operator signature verification, prevouts verification) // Ensure this method is called from the first input. assert(shPreimage.inputNumber == toByteString('00000000')) // Verify that the second input unlocks the correct aggregator script. assert(prevTx.depositAggregatorSPK == aggregatorTx.outputContractSPK) // Process deposits and update accounts. let accountsRootNew: Sha256 = prevTx.accountsRoot let totalAmtDeposited = 0n for (let i = 0; i < MAX_NODES_AGGREGATED; i++) { const deposit = deposits[i] if (deposit.address != toByteString('')) { accountsRootNew = this.applyDeposit( deposits[i], depositProofs[i], aggregatorTx.hashData, accounts[i], accountProofs[i], accountsRootNew ) } totalAmtDeposited += deposit.amount } // Update the bridge state and outputs. // (Compute new state hash, construct contract output, enforce outputs) }
Các bước được thực hiện bằng phương thức gửi tiền bao gồm:
Xử lý tiền gửi và cập nhật tài khoản :
- Lặp lại các khoản tiền gửi và áp dụng từng khoản tiền gửi vào tài khoản tương ứng bằng phương pháp applyDeposit.
Cập nhật trạng thái cầu và đầu ra :
Sau khi khoản tiền gửi được xử lý, tài khoản gốc Merkle mới sẽ được tính toán.
Tạo một hàm băm trạng thái mới đại diện cho trạng thái cầu nối được cập nhật.
Xây dựng sản lượng hợp đồng để cộng tổng số tiền đặt cọc vào số dư dư cầu.
Đảm bảo đầu ra ở định dạng mong đợi để duy trì tính toàn vẹn dữ liệu.
Phương pháp rút tiền xử lý các giao dịch rút tiền tổng hợp, cập nhật số dư tài khoản và chuẩn bị số tiền được phân bổ thông qua mở rộng rút tiền.
@method() public withdrawal( shPreimage: SHPreimage, sigOperator: Sig, prevTx: BridgeTransaction, // Previous bridge update transaction. aggregatorTx: AggregatorTransaction, // Root aggregator transaction. fundingPrevout: ByteString, withdrawals: FixedArray<WithdrawalData, typeof MAX_NODES_AGGREGATED>, accounts: FixedArray<AccountData, typeof MAX_NODES_AGGREGATED>, intermediateSumsArr: FixedArray<IntermediateValues, typeof MAX_NODES_AGGREGATED>, withdrawalProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED>, accountProofs: FixedArray<MerkleProof, typeof MAX_NODES_AGGREGATED> ) { // Common validation steps... // (Same as in previous contracts: sighash preimage check, operator signature verification, prevouts verification) // Ensure this method is called from the first input. assert(shPreimage.inputNumber == toByteString('00000000')) // Verify that the second input unlocks the correct aggregator script. assert(prevTx.withdrawalAggregatorSPK == aggregatorTx.outputContractSPK) // Process withdrawals and update accounts. let accountsRootNew: Sha256 = prevTx.accountsRoot let totalAmtWithdrawn = 0n for (let i = 0; i < MAX_NODES_AGGREGATED; i++) { const withdrawal = withdrawals[i] if (withdrawal.address != toByteString('')) { accountsRootNew = this.applyWithdrawal( withdrawal, withdrawalProofs[i], intermediateSumsArr[i], aggregatorTx.hashData, accounts[i], accountProofs[i], accountsRootNew ) } totalAmtWithdrawn += withdrawal.amount } // Update the bridge state and outputs. // (Compute new state hash, construct contract output, create expander output, enforce outputs) }
Các bước được thực hiện bằng phương thức rút tiền bao gồm:
Xử lý yêu cầu rút tiền và cập nhật tài khoản :
- Lặp lại các yêu cầu rút tiền và áp dụng mỗi lần rút tiền vào tài khoản tương ứng bằng phương pháp"applyDeposit".
Cập nhật trạng thái cầu và đầu ra :
Sau khi xử lý việc rút tiền, hãy tính toán gốc Merkle của tài khoản mới.
Tạo một hàm băm trạng thái mới đại diện cho trạng thái cầu nối được cập nhật.
Xây dựng một đầu ra hợp đồng trừ đi tổng số tiền rút từ số dư dư cầu.
Tạo đầu ra mở rộng cho hợp đồng mở rộng rút tiền trong đó chứa tổng số tiền rút.
Đảm bảo đầu ra ở định dạng mong đợi để duy trì tính toàn vẹn dữ liệu.
Mã nguồn hoàn chỉnh có thể được xem trên GitHub .
Hợp đồng mở rộng rút tiền
mở rộng là thành phần cuối cùng trong hệ thống cầu nối của chúng tôi và chịu trách nhiệm phân phối số tiền rút tổng hợp lại cho người dùng cá nhân dựa trên yêu cầu rút tiền của họ. Nó đảo ngược quá trình tổng hợp được thực hiện bởi công cụ tổng hợp rút tiền, mở rộng dữ liệu rút tiền tổng hợp trở lại các khoản thanh toán của người dùng cá nhân.
class WithdrawalExpander extends SmartContract { @prop() operator: PubKey constructor( operator: PubKey ) { super(...arguments) this.operator = operator } @method() public expand( shPreimage: SHPreimage, sigOperator: Sig, // Additional parameters... ) { // Expansion logic... } }
Chức năng cốt lõi của thiết mở rộng rút tiền được gói gọn trong phương pháp " mở rộng ". Phương pháp này chấp nhận dữ liệu rút tiền tổng hợp và mở rộng đệ quy thành các giao dịch rút tiền riêng lẻ, trả số tiền tương ứng cho người dùng.
Mở rộng sang nút nút lá : Nếu phương pháp mở rộng đến một nút lá (rút tiền một lần), nó sẽ xác thực dữ liệu rút tiền và tạo đầu ra thanh toán trực tiếp đến địa chỉ của người dùng.
if (isExpandingLeaves) { // If expanding to leaves, verify the withdrawal data. if (isExpandingPrevTxFirstOutput) { const hashWithdrawalData = WithdrawalAggregator.hashWithdrawalData(withdrawalData0) assert(hashWithdrawalData == prevAggregationData.prevH0) hashOutputs = sha256( WithdrawalExpander.getP2WPKHOut( GeneralUtils.padAmt(withdrawalData0.amount), withdrawalData0.address ) ) } else { const hashWithdrawalData = WithdrawalAggregator.hashWithdrawalData(withdrawalData1) assert(hashWithdrawalData == prevAggregationData.prevH1) hashOutputs = sha256( WithdrawalExpander.getP2WPKHOut( GeneralUtils.padAmt(withdrawalData1.amount), withdrawalData1.address ) ) } }
Mở rộng hơn nữa : Nếu phương pháp chưa đạt đến cấp độ nút lá, nó sẽ tiếp tục mở rộng, chia dữ liệu tổng hợp thành hai nhánh và tạo đầu ra để tiêu thụ bằng các giao dịch mở rộng hơn nữa.
else { // Verify current aggregation data matches previous aggregation data. const hashCurrentAggregationData = WithdrawalAggregator.hashAggregationData(currentAggregationData) if (isPrevTxBridge) { assert(hashCurrentAggregationData == prevTxBridge.expanderRoot) } else if (isExpandingPrevTxFirstOutput) { assert(hashCurrentAggregationData == prevAggregationData.prevH0) } else { assert(hashCurrentAggregationData == prevAggregationData.prevH1) } // Prepare outputs for the next level of expansion. let outAmt0 = 0n let outAmt1 = 0n if (isLastAggregationLevel) { const hashWithdrawalData0 = WithdrawalAggregator.hashWithdrawalData(withdrawalData0) const hashWithdrawalData1 = WithdrawalAggregator.hashWithdrawalData(withdrawalData1) assert(hashWithdrawalData0 == currentAggregationData.prevH0) assert(hashWithdrawalData1 == currentAggregationData.prevH1) outAmt0 = withdrawalData0.amount outAmt1 = withdrawalData1.amount } else { const hashNextAggregationData0 = WithdrawalAggregator.hashAggregationData(nextAggregationData0) const hashNextAggregationData1 = WithdrawalAggregator.hashAggregationData(nextAggregationData1) assert(hashNextAggregationData0 == currentAggregationData.prevH0) assert(hashNextAggregationData1 == currentAggregationData.prevH1) outAmt0 = nextAggregationData0.sumAmt outAmt1 = nextAggregationData1.sumAmt } // Construct outputs for further expansion. let expanderSPK = prevTxExpander.contractSPK if (isPrevTxBridge) { expanderSPK = prevTxBridge.expanderSPK } hashOutputs = sha256( GeneralUtils.getContractOutput(outAmt0, expanderSPK) + GeneralUtils.getContractOutput(outAmt1, expanderSPK) + GeneralUtils.getStateOutput(hashCurrentAggregationData) ) }
Tóm lại
Trong quá trình triển khai bằng chứng khái niệm này, chúng tôi đã phát triển hợp đồng cầu nối dựa trên Bitcoin được cung cấp bởi OP_CAT bằng cách sử dụng Ngôn ngữ cụ thể miền (DSL) được nhúng sCrypt . Cây cầu sử dụng các hợp đồng đệ quy và Merkle trees để gửi và rút tiền theo nhóm một cách hiệu quả trong khi vẫn duy trì tính toàn vẹn và bảo mật của tài khoản người dùng. Bằng cách thiết kế và triển khai bốn hợp đồng thông minh: Bộ tổng hợp tiền gửi , Bộ tổng hợp rút tiền, Bộ mở rộng cầu nối mở rộng rút tiền , chúng tôi cung cấp một phương pháp để quản lý các tương tác có trạng thái trên Bitcoin , tạo điều kiện cho khả năng tương tác với các mạng lớp 2 như Starknet. Công việc này cung cấp nền tảng kỹ thuật để xây dựng các cầu nối cấp sản xuất, có khả năng nâng cao mở rộng và chức năng trong hệ sinh thái Bitcoin .
Tất cả việc triển khai mã và kiểm tra từ đầu đến cuối đều có sẵn trên GitHub .